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

Is there a way to define sum type? #1

Open
srghma opened this issue May 4, 2020 · 15 comments
Open

Is there a way to define sum type? #1

srghma opened this issue May 4, 2020 · 15 comments

Comments

@srghma
Copy link

srghma commented May 4, 2020

How to define data Foo = Bar | Baz?

I don't see anything similar

@flip111
Copy link
Member

flip111 commented May 4, 2020

It's still very early stage, please come back later :))

@srghma
Copy link
Author

srghma commented May 4, 2020

@paluh
Copy link
Member

paluh commented May 4, 2020

@srghma Yeah. We should definitely handle Sum types. Finally we want to cover the whole PS :-)

@paluh
Copy link
Member

paluh commented May 4, 2020

I want to also point out that I've made a possible mistake and initially was looking into purescript cst as a main source of inspiration. AST from cst is designed for a parser and we should probably look more into AST inside the compiler too as you suggested above @srghma. This internal AST is already used for printing:

https://github.com/purescript/purescript/tree/master/src/Language/PureScript/Pretty/

@paluh
Copy link
Member

paluh commented May 4, 2020

So I copied code mainly from here (this is representation used by parser - close to the "source code"):

https://github.com/purescript/purescript/blob/ab72a72ffa842d5e220e9c97c1f0f8da828a69a0/lib/purescript-cst/src/Language/PureScript/CST/Types.hs

and not from here (this is representation used to represent language constructs internally - it has a printer):

https://github.com/purescript/purescript/tree/ab72a72ffa842d5e220e9c97c1f0f8da828a69a0/lib/purescript-ast/src/Language/PureScript/AST

The question is: which is a better inspiration for the simplest possible codegen? What do you think? Maybe we should ask PS core team :-)

@paluh
Copy link
Member

paluh commented May 4, 2020

It is also worth to add that purty uses cst representation for its codegen. I think that the reason is that it needs to be able to work closely with and transform existing source code.

P.S.
@srghma @flip111 - sorry for spamming this thread. I can move these comments into a separate issue or move them to the wiki or documentation repo :-)

@srghma
Copy link
Author

srghma commented May 5, 2020

@paluh
Copy link
Member

paluh commented May 5, 2020

@srghma @flip111 @jvliwanag
Should we go and rename this lib into purescript-ps-cst and just focus on porting the original cst lib into the PS land here? What do you think Guys?

When we commit to do only cst approach here it seems that it will be possibility to build also a pretty printing library on top.... on the other hand I think it is better to just contribute to purty instead :-P

@srghma
Copy link
Author

srghma commented May 5, 2020

research

from cst

data Type a
  = TypeVar a (Name Ident) -- e.g. `a` in `Foo a`
  | TypeConstructor a (QualifiedName (N.ProperName 'N.TypeName)) -- e.g. `Text` in `Foo Text`
  | TypeWildcard a SourceToken -- e.g. this is `_` in `foo :: _`
  | TypeString a SourceToken PSString -- e.g. `"foo"` in `foo = SProxy :: SProxy "foo"`

  | TypeHole a (Name Ident) -- not in ast, e.g. `?hole` in `foo :: ?hole`

  | TypeOp a (Type a) (QualifiedName (N.OpName 'N.TypeOpName)) (Type a)  -- e.g. it's `$` or `<<<` in `data Foo = Array <<< Maybe $ Int`
  | TypeOpName a (QualifiedName (N.OpName 'N.TypeOpName)) -- not in ast, this is `(..)` in `foo :: Foo ((..) :: Type)`

  | TypeApp a (Type a) (Type a) -- e.g. `Eff` is `TypeApp (TypeApp "Eff" (ROW)) Unit)` in `forall e. Eff ( console :: CONSOLE, foo :: FOO | e ) Unit`

  | TypeForall a SourceToken (NonEmpty (TypeVarBinding a)) SourceToken (Type a)
  | TypeConstrained a (Constraint a) SourceToken (Type a) -- e.g. in `foo :: Applicative f => Traversal f => f a` it is `TypeConstrained (Constraint ....) (TypeConstrained (Constraint ....) (f a))`

  | TypeRow a (Wrapped (Row a)) -- e.g. `(...)`
  | TypeRecord a (Wrapped (Row a)) -- e.g. `{ ... }`

  | TypeArr a (Type a) SourceToken (Type a) -- not in ast, e.g. `foo :: Foo -> Bar` is eq to `TypeArr ... (TypeConstructor Foo) ... (TypeConstructor Bar)`
  | TypeArrName a SourceToken -- not in ast, this is `(->)` in `foo :: Foo (->)`
  | TypeKinded a (Type a) SourceToken (Kind a) -- e.g. this is `(a :: Type)` in `data Foo (a :: Type)`
  | TypeParens a (Wrapped (Type a)) -- e.g. this is `(Bar a)` in `data Foo = Foo (Bar a)`

from ast

data Type a
  = TUnknown a Int -- no in cst

  | TypeVar a Text
  | TypeConstructor a (Qualified (ProperName 'TypeName))
  | TypeWildcard a (Maybe Text)
  | TypeLevelString a PSString

  | TypeOp a (Qualified (OpName 'TypeOpName))
  | TypeApp a (Type a) (Type a)

  | ForAll a Text (Maybe (Kind a)) (Type a) (Maybe SkolemScope)
  | ConstrainedType a (Constraint a) (Type a)

  | Skolem a Text Int SkolemScope -- not in cst

  | REmpty a
  | RCons a Label (Type a) (Type a)

  | KindedType a (Type a) (Kind a)
  | ParensInType a (Type a)

  | BinaryNoParensType a (Type a) (Type a) (Type a) -- not in ast

data Bar a b c
  = Bar a -- This is a comment
  | Baz Int
  | Qux (Foo a) (Bar a b c)

is parsed to

https://pastebin.com/5G4cStkA


foreign import main_ :: forall e. Eff ( console :: CONSOLE, foo :: FOO | e ) Unit

https://pastebin.com/GRd6J7je (not all is pretty-printed)


module Kinded where

data Foo (a :: Type)

data Bar
  = Baz (Boolean :: Type)

https://pastebin.com/vzR6tDtW


module Ado where

type Foo = Array $ Int

https://pastebin.com/LiNGBJeG


module Ado where

type Compose f g a = f (g a)
infixr 9 type Compose as <<<

https://pastebin.com/KBw6vjF4


module Ado where

foo :: Foo _

https://pastebin.com/nLpPtVtS


import Prelewd
import Prelude
import Control.Monad.Eff.Console (CONSOLE, log)
import Data.Functor (class Functor, map, void)
import Data.List (cons, nil)
import Data.Maybe (Maybe(Just, Nothing), maybe)
import Prelude
  ( class EuclideanRing
  , class Semiring
  , Ordering(EQ, GT, LT)
  , Unit
  , Void
  , compose
  , flap
  , one
  , (&&)
  , (<<<)
  , (~>)
  )
import Data.Array
  ( head
  , tail
  )
  as Array
import Data.List as List
import Data.Maybe
  as Maybe

https://pastebin.com/nKg842PP


which is a better inspiration for the simplest possible codegen? What do you think?

I think the purescript-cst is better than ast for us

Should we go and rename this lib into purescript-ps-cst

I think yes, we should rename

focus on porting the original cst lib into the PS land here
on the other hand I think it is better to just contribute to purty instead

I'll try to add sum types support. As of purty written in purescript - not in my scope)

@jvliwanag
Copy link
Member

jvliwanag commented May 5, 2020

Just to give a bit of context, the original goal of this project has been to assist in writing ffi bindings to JS libraries. In fact @paluh already has working bindings for react-mui from which he has derived this project from. The approach for writing ffi bindings is interesting. A program interacts with the typescript compiler which then reads through the typescript source code. This program utilizes the codegen library to emit purescript code. As such, one can easily update the purescript ffi just by rerunning the codegen.

Now, the codegen however is purpose built for the react-mui library. Doing it for other js/ts project will involve a bit of copying code.

In order to help with this, we've decided to fork off the codegen portion of the purescript-react-mui into this project and remove the mui specific stuff. We've also expanded the scope of this to (ideally) emit any purescript code. From which we can build code patterns that will later on be the backbone of doing automated ffi.

Expanding the scope however, we then end up with a number of options:

  1. Keep the existing simplicity of this current library. Meaning let's not target supporting the entire purescript cst/ast as it will undoubtedly more complex. Possibly expose unsafe functions to insert code portions we don't support directly.

  2. Embrace that we want to write all possible purescript code and port the cst portion of purescript (written in haskell) onto purescript. Then create a printer (possibly taking hints from purty).

  3. Don't port anything. Just work directly on haskell utilizing purescript-cst. Perhaps create a variant of purty that's designed to be used as a library.

The advantage of (2) as a user is that it's easy to tie in other js based tooling. Ex - typescript compiler. As a user of purescript, it is also easier to use purescript libraries. The disadvantage is that it will be hard to keep the library up to date. Also, doing this is not a simple task.

The advantage of (3) is we get to work directly with the purescript compiler codebase. Problem is it's in haskell. An option that lies between (2) and (3) is keep the code in haskell. Then instead of writing a port as described in (2), we instead write purescript bindings to the haskell library (though I'm not exactly sure how to do this.)

To be honest, I've been on and off which approach to take. An early attempt at (3) by transforming purty to a library is -- https://gitlab.com/jvliwanag/purty/-/tree/6.1.0-lib . But I haven't visited it lately to make my suggestion on this. For me though, it's a choice between (1) and (3).

@srghma
Copy link
Author

srghma commented May 5, 2020

the 2 is ideal, but maybe hard

@srghma
Copy link
Author

srghma commented May 6, 2020

@paluh
Copy link
Member

paluh commented May 6, 2020

@srghma Thanks for your interest and your research.

  1. Keep the existing simplicity of this current library. Meaning let's not target supporting the entire purescript cst/ast as it will undoubtedly more complex. Possibly expose unsafe functions to insert code portions we don't support directly.

  2. Embrace that we want to write all possible purescript code and port the cst portion of purescript (written in haskell) onto purescript. Then create a printer (possibly taking hints from purty).

@jvliwanag . To be honest I'm only considering these two options because my main focus is to work on TS/PS tooling and interaction... (Or I'm just cached by a "Commitment/Consistency" trap :-)).
I'm also concerned that porting CST involves more work and adds complexity. On the other hand it is easier to stay consistent and correct with the compiler representation and provide somewhat "more correct AST".
To be honest I have to first finish my work on the mui migration so it works based on this separated AST and make a release there :-)

@srghma srghma mentioned this issue May 7, 2020
@jvliwanag
Copy link
Member

looks like @srghma taking on the cst port ;) Very much looking forward to #4 !

@paluh
Copy link
Member

paluh commented May 11, 2020

Wow! @srghma PR looks incredible!

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

No branches or pull requests

4 participants