Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polymorphic datatype #7

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

markfarrell
Copy link
Collaborator

Allows define-datatype to take type parameters, as discussed in #2.

e.g.

(define-datatype (Optional a)
  [Some (a)]
  [None ()])

Note: changes syntax of define-datatype; might not be quite ready to merge for that reason, if e.g. examples need to be updated.

cc/ @andmkent

@pnwamk
Copy link
Owner

pnwamk commented Dec 21, 2015

Cool - let me look at adding a few tweaks so specifying type variables is optional (i.e. the old syntax is valid too) and I'll report (today or tomorrow).

@markfarrell
Copy link
Collaborator Author

Yeah, sounds good. 👍

@markfarrell
Copy link
Collaborator Author

Easiest solution involves duplicate code. Should be possible to simplify?

@markfarrell
Copy link
Collaborator Author

On a related note: having an issue with a "polymorphic" type-case and likewise match:

(: a (Optional String))
(define a
  (Some "test"))

(: b String)
(define b 
  (type-case Optional a
    [(Some str) => str]
    [else => "error"]))

(: c String)
(define c
  (match a 
    [(Some str) str]
    [_ "error"]))
. Type Checker: type mismatch
  expected: String
  given: Any in: str
. Type Checker: type mismatch
  expected: String
  given: Any in: str
. Type Checker: Summary: 2 errors encountered in:
  str
  str

Currently have to cast to resolve:

(: a (Optional String))
(define a
  (Some "test"))

(: b String)
(define b 
  (type-case Optional a
    [(Some str) => 
     (cast str String)]
    [else => "error"]))

(: c String)
(define c
  (match a 
    [(Some str) 
     (cast str String)]
    [_ "error"]))

@pnwamk
Copy link
Owner

pnwamk commented Dec 21, 2015

Duplicate code: We should be able to use the features of the syntax/parse library to avoid duplicate code (using features like ~or, ~bind, and syntax classes).

Polymorphic issues: There's a fundamental issue with the current approach: assigning polymorphic variables to a struct that does not have any fields of the polymorphic type in essence ignores the polymorphic variables. For example, the following typechecks:

#lang typed/racket

(struct: (A) Foo () #:transparent)

(define (foo [x : (Foo Integer)]) : (Foo String)
  x)

I think this indicates I need to rewrite things to use a define-type and a union instead of an empty parent struct and inheritance.

@pnwamk
Copy link
Owner

pnwamk commented Dec 21, 2015

Yikes - tinkered with that a little longer than I thought I would =)

Well for now I threw together something that supports both non-polymorphic and polymorphic definitions:

#lang typed/racket

(require "datatype.rkt")
(define-type Int Integer)

(define-datatype (Opt A)
  [Some (A)]
  [None ()])

(define (extract-int [x : (Opt Int)]) : Integer
  (Opt-case [#:inst Int]
   x
   [(Some i) => i]
   [(None) => -1]))

(define-datatype Expr
  [Var (Symbol)]
  [Lambda (Symbol Expr)]
  [App (Expr Expr)])

(: foo (Expr -> Symbol))
(define (foo e)
  (Expr-case
   e
   [(Var x) => x]
   [(Lambda y _) => y]
   [(App _ _) => 'app]))

I ended up just rewriting it from scratch more or less---I think it's a little easier to read now, with the catch being it no longer does the crazy macro generating macro stuff and now there is not a universal type-case but a case macro generated for each datatype. I'm sure with a little effort you could merge something like what I threw together here with the type-case stuff in the original definitions.

I don't have a lot of time to dedicate to this right now so... I'll leave what I have so far and if you like you can tweak/modify/etc... it however you see fit.

@pnwamk
Copy link
Owner

pnwamk commented Dec 21, 2015

Oh - and the syntax choices were rather arbitrary (e.g. [#:inst ...] was easy to parse =)-- so if you wanted to play around with it and pick something that looks better or is easier to read/type etc... by all means! =)

@markfarrell
Copy link
Collaborator Author

Cool - thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants