Hi,
I tried to port a Haskell data type to racket. Can I create these types ? What is the equivalent racket structure ?
(define-struct Error i e ([ errorOffset : Offset ]
[ error : ErrorType i e])
(define-struct ErrorType I e
([ EndOfInput]
[ Unexpected I]
[ Expected I e]
[ ExpectedEndOfFile I]
[ BeginningOfInput I]
[ Empty])
When I split the structure like this it compiles.
struct Literal ([i : Char ]))
(struct Plus ())
(struct Minus ())
(struct Div ())
(struct InvalidChar ([i : Char]))
So if I follow this guideline I get the following code.
#lang typed/racket
(require racket/list)
(struct Offset ([Offset : Int]))
(define (operator c )
(match c
['+' Plus]
['-' Minus]
['/' Div]))
(struct Literal ([i : Char ]))
(struct Plus ())
(struct Minus ())
(struct Div ())
(struct InvalidChar ([i : Char]))
(struct: EndOfInput())
(struct: Empty())
(struct: Unexpected([i : Char]))
(struct: Expected([i : Offset] [e : Char]))
(struct: ExpectedEndOfFile([i : Char]))
(struct: BeginningOfInput ([i : Char]))
(define-type (ErrorType i e)
(U (EndOfInput)
( Unexpected i)
( Expected i e)
( ExpectedEndOfFile i)
( BeginningOfInput i)
( Empty)))
(define-type (Error i e) (U Offset
(ErrorType i e)))
which doesn't compile either.
/Applications/Racket v8.8/share/pkgs/typed-racket-lib/typed-racket/utils/tc-utils.rkt:57:43: Type Checker: Error in macro expansion -- cannot apply a non-polymorphic type
; type: #(struct:Empty ())
; arguments: ()
; in: here
Thanks,
Mohan
Hi,
I tried to port a Haskell data type to racket. Can I create these types ? What is the equivalent racket structure ?
What are the Haskell data types you are porting?
I am writing a parser and managed to put this Haskell code together mainly by starting with the data structures.
Haskell
data Operator i = Literal i| Plus | Minus | Div
| InvalidChar I
deriving (Show, Eq)
data Error i e = Error
{ errorOffset :: Offset
, error :: ErrorType I e
} deriving (Eq, Show)
data ErrorType I e
= EndOfInput
| Unexpected I
| Expected I e
| ExpectedEndOfFile I
| BeginningOfInput I
| Empty
deriving (Eq, Show)
type Offset = Int
operator :: Char -> Operator Char
operator c | c == '+' = Plus
| c == '-' = Minus
| c == '/' = Div
scanner :: Offset -> ErrorType Offset Char-> String -> Either [Error Offset (ErrorType Offset Char)] [Operator Char]
scanner offset error (x:xs)
| isDigit x = tokenize offset error (Literal x)
| x == '+' = tokenize offset error (operator x)
| otherwise = tokenize offset error (InvalidChar x)
where
tokenize offset error t =
case scanner offset error XS of
Left err -> Left err
Right tokens -> Right (t : tokens)
scanner offset error "" = Right []
I did a similar exercise using racket. Now I started with the same data structures. I managed
to pass the compiler phase here. I don't see errors but the code is not executed. This is my first racket code. So I
want to know if this is reasonable code. At this time I don't fully understand the type system since I am just a code monkey.
#lang typed/racket
(require racket/list)
(define (operator c )
(match c
['+' Plus]
['-' Minus]
['/' Div]))
(struct Literal ([i : Char ]))
(struct Plus ())
(struct Minus ())
(struct Div ())
(struct InvalidChar ([i : Char]))
(struct EndOfInput())
(struct Empty() )
(struct (i) Unexpected([val : I]))
(define-type (Expected i e) (U Integer Char))
(struct (i) ExpectedEndOfFile([val : I]))
(struct (i) BeginningOfInput ([val : I]))
(define-type (ErrorType I e)
(U EndOfInput Empty
( Unexpected i)
( Expected I e)
( ExpectedEndOfFile i)
( BeginningOfInput i)))
;; ( Empty)))
(define-type (Error i e) (U Integer
(ErrorType i e)))
The Haskell code returns an Either
. I am trying to understand how this is done using Racket.
The compiler doesn't accept the commented lines. Error is in original post.
Thanks.
Update : There is no compiler error as I removed braces around (Empty)
and (EndOfInput)
Here's a more straightforward translation of part of the Haskell code to Typed Racket to get you started:
#lang typed/racket/base
(struct (a) literal ([value : a])
#:type-name Literal
#:transparent)
(struct (a) invalid ([value : a])
#:type-name Invalid
#:transparent)
(define-type (Operator a) (U (Literal a) 'Plus 'Minus 'Div (Invalid a)))
(: operator : Char -> (Operator Char))
(define (operator ch)
(case ch
((#\+) 'Plus)
((#\-) 'Minus)
((#\/) 'Div)
(else (invalid ch))))
Note things like the use of symbols instead of structs for many of the values, adding an explicit type signature (Type inference is nice, but in my experience, TR's leaves something to be desired compared to languages like ocaml or haskell), and creating instances of structures instead of trying to return a structure type name like you are doing in your operator
function
2 Likes
Thanks. I am trying to understand this better.
I defined (define-type (Expected i e) (U Integer Char))
so that the complex type with two parameters is accepted. I feel there is a better way.
How can I declare a 'struct' with two parameters ? Should that be define-type
?
(define-type (ErrorType i e)
(U Empty EndOfInput
( Unexpected i)
( Expected i e)
( ExpectedEndOfFile i)
( BeginningOfInput i)))
Mohan
Hello,
Yes. I think some video links can be included in the wiki.
-
https://t.co/ZAXYnUbAzW , LambdaConf 2015 - Mark Farrell's Introduction to Typed Racket is quite Helpful.
-
Kristopher Micinski's Youtube Racket Videos.
-
Jeremy Siek's Racket compiler book and Indiana University's course link.
Discord is a low-volume forum. I think.
Thanks,
Mohan
1 Like