Create New data types

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

Hi Mohan

Saw your question on r/racket and it seemed like it was related to this topic?

I hope my comment there was helpful: https://www.reddit.com/r/Racket/comments/13bvxtn/parsing_a_string_of_chars/jje89w5/?utm_source=share&utm_medium=ios_app&utm_name=ioscss&utm_content=1&utm_term=1&context=3

Best regards

Stephen

Hello,

Yes. I think some video links can be included in the wiki.

  1. https://t.co/ZAXYnUbAzW , LambdaConf 2015 - Mark Farrell's Introduction to Typed Racket is quite Helpful.

  2. Kristopher Micinski's Youtube Racket Videos.

  3. Jeremy Siek's Racket compiler book and Indiana University's course link.

Discord is a low-volume forum. I think.

Thanks,
Mohan

1 Like