Skip to content

Commit aa253b3

Browse files
committed
Add support for parameterised types
1 parent c94c35e commit aa253b3

File tree

8 files changed

+140
-45
lines changed

8 files changed

+140
-45
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased changes
44

5+
- Add support for parameterised types
56
- Handle Basics.() in isConstructor check
67
- Simplify case-of-case expressions
78

elm-syntax.cabal

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ cabal-version: 1.12
44
--
55
-- see: https://github.com/sol/hpack
66
--
7-
-- hash: 0ef776b3daae1808ec6d9199f2bba0aa2018977a5ba9d2f847c6940ecbcf85aa
7+
-- hash: 4852b94fa3c78222b53566d23352534c8fab264e301bc13f0c11d479c70ec497
88

99
name: elm-syntax
1010
version: 0.2.0.0
@@ -45,7 +45,7 @@ library
4545
build-depends:
4646
base >=4.7 && <5
4747
, bound >=2.0.0
48-
, deriving-compat >=0.5
48+
, deriving-compat >=0.5.0
4949
, hashable >=1.2.5
5050
, prettyprinter >=1.2.1
5151
, text >=1.2.0
@@ -63,7 +63,7 @@ test-suite elm-syntax-test
6363
build-depends:
6464
base >=4.7 && <5
6565
, bound >=2.0.0
66-
, deriving-compat >=0.5
66+
, deriving-compat >=0.5.0
6767
, elm-syntax
6868
, hashable >=1.2.5
6969
, prettyprinter >=1.2.1

package.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ dependencies:
2828
- prettyprinter >= 1.2.1
2929
- text >= 1.2.0
3030
- unordered-containers >= 0.2.8
31+
- deriving-compat >= 0.5.0
3132

3233
ghc-options:
3334
- -Wall

src/Language/Elm/Definition.hs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,25 @@ module Language.Elm.Definition where
22

33
import Data.Void
44

5+
import Bound (Scope)
6+
import qualified Bound
7+
58
import Language.Elm.Expression (Expression)
69
import qualified Language.Elm.Expression as Expression
710
import qualified Language.Elm.Name as Name
811
import Language.Elm.Type (Type)
912
import qualified Language.Elm.Type as Type
1013

1114
data Definition
12-
= Constant !Name.Qualified (Type Void) (Expression Void)
13-
| Type !Name.Qualified [(Name.Constructor, [Type Void])]
14-
| Alias !Name.Qualified (Type Void)
15+
= Constant !Name.Qualified !Int (Scope Int Type Void) (Expression Void)
16+
| Type !Name.Qualified !Int [(Name.Constructor, [Scope Int Type Void])]
17+
| Alias !Name.Qualified !Int (Scope Int Type Void)
1518
deriving (Eq, Ord, Show)
1619

1720
name :: Definition -> Name.Qualified
18-
name (Constant n _ _) = n
19-
name (Type n _) = n
20-
name (Alias n _) = n
21+
name (Constant n _ _ _) = n
22+
name (Type n _ _) = n
23+
name (Alias n _ _) = n
2124

2225
foldMapGlobals
2326
:: Monoid m
@@ -26,15 +29,15 @@ foldMapGlobals
2629
-> m
2730
foldMapGlobals f def =
2831
case def of
29-
Constant qname type_ expr ->
32+
Constant qname _ type_ expr ->
3033
f qname <>
31-
Type.foldMapGlobals f type_ <>
34+
Type.foldMapGlobals f (Bound.fromScope type_) <>
3235
Expression.foldMapGlobals f expr
3336

34-
Type qname constrs ->
37+
Type qname _ constrs ->
3538
f qname <>
36-
foldMap (foldMap (foldMap (Type.foldMapGlobals f))) constrs
39+
foldMap (foldMap (foldMap (Type.foldMapGlobals f . Bound.fromScope))) constrs
3740

38-
Alias qname type_ ->
41+
Alias qname _ type_ ->
3942
f qname <>
40-
Type.foldMapGlobals f type_
43+
Type.foldMapGlobals f (Bound.fromScope type_)

src/Language/Elm/Expression.hs

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
{-# language DeriveGeneric #-}
55
{-# language DeriveTraversable #-}
66
{-# language OverloadedStrings #-}
7+
{-# language ScopedTypeVariables #-}
78
{-# language StandaloneDeriving #-}
89
{-# language TemplateHaskell #-}
910
module Language.Elm.Expression where
1011

1112
import Bound
1213
import Bound.Var (unvar)
1314
import Control.Monad
15+
import Data.Bifoldable
16+
import Data.Bifunctor
1417
import Data.Eq.Deriving
1518
import Data.Ord.Deriving
1619
import Data.String
@@ -41,18 +44,55 @@ instance Applicative Expression where
4144
(<*>) = ap
4245

4346
instance Monad Expression where
44-
Var v >>= f = f v
45-
Global g >>= _ = Global g
46-
App e1 e2 >>= f = App (e1 >>= f) (e2 >>= f)
47-
Let e s >>= f = Let (e >>= f) (s >>>= f)
48-
Lam s >>= f = Lam (s >>>= f)
49-
Record fs >>= f = Record [(fname, e >>= f) | (fname, e) <- fs]
50-
Proj f >>= _ = Proj f
51-
Case e brs >>= f = Case (e >>= f) [(pat, s >>>= f) | (pat, s) <- brs]
52-
List es >>= f = List ((>>= f) <$> es)
53-
String s >>= _ = String s
54-
Int n >>= _ = Int n
55-
Float f >>= _ = Float f
47+
(>>=) =
48+
flip $ bind Global
49+
50+
bind :: forall v v'. (Name.Qualified -> Expression v') -> (v -> Expression v') -> Expression v -> Expression v'
51+
bind global var expression =
52+
case expression of
53+
Var v ->
54+
var v
55+
56+
Global g ->
57+
global g
58+
59+
App t1 t2 ->
60+
App (bind global var t1) (bind global var t2)
61+
62+
Let e s ->
63+
Let (bind global var e) (bindScope s)
64+
65+
Lam s ->
66+
Lam (bindScope s)
67+
68+
Record fields ->
69+
Record $ second (bind global var) <$> fields
70+
71+
Proj fname ->
72+
Proj fname
73+
74+
Case scrutinee branches ->
75+
Case
76+
(bind global var scrutinee)
77+
(second bindScope <$> branches)
78+
79+
List es ->
80+
List $ bind global var <$> es
81+
82+
String s ->
83+
String s
84+
85+
Int i ->
86+
Int i
87+
88+
Float f ->
89+
Float f
90+
where
91+
bindScope :: Scope b Expression v -> Scope b Expression v'
92+
bindScope =
93+
toScope .
94+
bind (fmap F . global) (unvar (pure . B) (fmap F . var)) .
95+
fromScope
5696

5797
deriving instance Eq v => Eq (Expression v)
5898
deriving instance Ord v => Ord (Expression v)
@@ -154,7 +194,7 @@ foldMapGlobals f expr =
154194
Case e branches ->
155195
foldMapGlobals f e <>
156196
foldMap
157-
(\(pat, scope) -> Pattern.foldMapGlobals f pat <> foldMapGlobals f (Bound.fromScope scope))
197+
(bifoldMap (Pattern.foldMapGlobals f) (foldMapGlobals f .Bound.fromScope))
158198
branches
159199

160200
List es ->

src/Language/Elm/Pretty.hs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,12 @@ extendPat env pat =
152152

153153
occurrences =
154154
HashSet.toList occurrencesSet
155+
in
156+
extendMany env occurrences
155157

158+
extendMany :: Environment v -> [Int] -> Environment (Bound.Var Int v)
159+
extendMany env occurrences =
160+
let
156161
bindings =
157162
HashMap.fromList $
158163
zip occurrences $ freshLocals env
@@ -163,7 +168,7 @@ extendPat env pat =
163168
lookupVar i =
164169
case HashMap.lookup i bindings of
165170
Nothing ->
166-
error "Unbound pattern variable"
171+
error "Language.Elm.Pretty unbound pattern variable"
167172

168173
Just v ->
169174
v
@@ -366,11 +371,18 @@ twoLineOperator qname =
366371
definition :: Environment Void -> Definition -> Doc ann
367372
definition env def =
368373
case def of
369-
Definition.Constant (Name.Qualified _ name) t e ->
374+
Definition.Constant (Name.Qualified _ name) numTypeParams t e ->
370375
let
371-
(names, body) = lambdas env e
376+
typeParams =
377+
[0..numTypeParams - 1]
378+
379+
typeEnv =
380+
extendMany env typeParams
381+
382+
(names, body) =
383+
lambdas env e
372384
in
373-
pretty name <+> ":" <+> nest 4 (type_ env 0 t) <> line <>
385+
pretty name <+> ":" <+> nest 4 (type_ typeEnv 0 $ Bound.fromScope t) <> line <>
374386
(case names of
375387
[] ->
376388
pretty name <+> "="
@@ -379,16 +391,30 @@ definition env def =
379391
pretty name <+> hsep (local <$> names) <+> "=") <>
380392
line <> indent 4 body
381393

382-
Definition.Type (Name.Qualified _ name) constrs ->
383-
"type" <+> pretty name <> line <>
394+
Definition.Type (Name.Qualified _ name) numParams constrs ->
395+
let
396+
params =
397+
[0..numParams - 1]
398+
399+
env' =
400+
extendMany env params
401+
in
402+
"type" <+> pretty name <+> hsep (local . locals env' . Bound.B <$> params) <> line <>
384403
indent 4 ("=" <+>
385404
mconcat
386405
(intersperse (line <> "| ")
387-
[constructor c <+> hsep (type_ env (appPrec + 1) <$> ts) | (c, ts) <- constrs]))
406+
[constructor c <+> hsep (type_ env' (appPrec + 1) . Bound.fromScope <$> ts) | (c, ts) <- constrs]))
388407

389-
Definition.Alias (Name.Qualified _ name) t ->
390-
"type alias" <+> pretty name <+> "=" <> line <>
391-
indent 4 (type_ env 0 t)
408+
Definition.Alias (Name.Qualified _ name) numParams t ->
409+
let
410+
params =
411+
[0..numParams - 1]
412+
413+
env' =
414+
extendMany env params
415+
in
416+
"type alias" <+> pretty name <+> hsep (local . locals env' . Bound.B <$> params) <+> "=" <> line <>
417+
indent 4 (type_ env' 0 $ Bound.fromScope t)
392418

393419
-------------------------------------------------------------------------------
394420
-- * Expressions

src/Language/Elm/Simplification.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ simplifyDefinition
2828
-> Definition
2929
simplifyDefinition def =
3030
case def of
31-
Definition.Constant name type_ expr ->
32-
Definition.Constant name type_ $ simplifyExpression expr
31+
Definition.Constant name numTypeParams type_ expr ->
32+
Definition.Constant name numTypeParams type_ $ simplifyExpression expr
3333

3434
Definition.Type {} ->
3535
def

src/Language/Elm/Type.hs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22
{-# language DeriveFunctor #-}
33
{-# language DeriveTraversable #-}
44
{-# language OverloadedStrings #-}
5+
{-# language TemplateHaskell #-}
56
module Language.Elm.Type where
67

78
import Control.Monad
9+
import Data.Bifunctor
10+
import Data.Eq.Deriving (deriveEq1)
811
import Data.Foldable
12+
import Data.Ord.Deriving (deriveOrd1)
913
import Data.String
14+
import Text.Show.Deriving (deriveShow1)
1015

1116
import qualified Language.Elm.Name as Name
1217

@@ -18,16 +23,35 @@ data Type v
1823
| Record [(Name.Field, Type v)]
1924
deriving (Eq, Ord, Show, Functor, Foldable, Traversable)
2025

26+
deriveEq1 ''Type
27+
deriveOrd1 ''Type
28+
deriveShow1 ''Type
29+
2130
instance Applicative Type where
2231
pure = Var
2332
(<*>) = ap
2433

2534
instance Monad Type where
26-
Var v >>= f = f v
27-
Global g >>= _ = Global g
28-
App t1 t2 >>= f = App (t1 >>= f) (t2 >>= f)
29-
Fun t1 t2 >>= f = Fun (t1 >>= f) (t2 >>= f)
30-
Record fields >>= f = Record [(n, t >>= f) | (n, t) <- fields]
35+
(>>=) =
36+
flip $ bind Global
37+
38+
bind :: (Name.Qualified -> Type v') -> (v -> Type v') -> Type v -> Type v'
39+
bind global var type_ =
40+
case type_ of
41+
Var v ->
42+
var v
43+
44+
Global g ->
45+
global g
46+
47+
App t1 t2 ->
48+
App (bind global var t1) (bind global var t2)
49+
50+
Fun t1 t2 ->
51+
Fun (bind global var t1) (bind global var t2)
52+
53+
Record fields ->
54+
Record $ second (bind global var) <$> fields
3155

3256
instance IsString (Type v) where
3357
fromString = Global . fromString

0 commit comments

Comments
 (0)