1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE GADTs #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6{-# LANGUAGE LambdaCase #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE UnicodeSyntax #-}
10{-# LANGUAGE ViewPatterns #-}
11{-# LANGUAGE Arrows          #-}
12
13module Tutorial where
14
15-- import Abt.Class
16-- import Abt.Types
17-- import Abt.Concrete.LocallyNameless
18
19import Control.Applicative
20import Control.Monad.Trans.State.Strict
21import Control.Monad.Trans.Maybe
22import Control.Monad.Trans.Except
23-- import Data.Vinyl
24import Prelude hiding (pi)
25
26-- | We'll start off with a monad in which to manipulate ABTs; we'll need some
27-- state for fresh variable generation.
28--
29newtype M α
30  = M
31  { _MState Int α
32  } deriving (Functor, Applicative, Monad)
33
34-- | We'll run an ABT computation by starting the variable counter at @0@.
35--
36runMM αα
37runM (M m) = evalState m 0
38
39-- | Check out the source to see fresh variable generation.
40--
41instance MonadVar Var M where
42  fresh = M $ do
43    nget
44    let n' = n + 1
45    put n'
46    return $ Var Nothing n'
47
48  named a = do
49    vfresh
50    return $ v { _varName = Just a }
51
52-- | Next, we'll define the operators for a tiny lambda calculus as a datatype
53-- indexed by arities.
54--
55data Lang ns where
56  LAMLang '[S Z]
57  APP ∷ Lang '[Z, Z]
58  PILang '[Z, S Z]
59  UNIT ∷ Lang '[]
60  AXLang '[]
61
62instance Show1 Lang where
63  show1 = \case
64    LAM → "lam"
65    APP → "ap"
66    PI → "pi"
67    UNIT → "unit"
68    AX → "<>"
69
70instance HEq1 Lang where
71  heq1 LAM LAM = Just Refl
72  heq1 APP APP = Just Refl
73  heq1 PI PI = Just Refl
74  heq1 UNIT UNIT = Just Refl
75  heq1 AX AX = Just Refl
76  heq1 _ _ = Nothing
77
78lam ∷ Tm Lang (S Z) → Tm0 Lang
79lam e = LAM $$ e :& RNil
80
81app ∷ Tm0 Lang → Tm0 Lang → Tm0 Lang
82app m n = APP $$ m :& n :& RNil
83
84ax ∷ Tm0 Lang
85ax = AX $$ RNil
86
87unit ∷ Tm0 Lang
88unit = UNIT $$ RNil
89
90pi ∷ Tm0 Lang → Tm Lang (S Z) → Tm0 Lang
91pi α xβ = PI $$ α :& xβ :& RNil
92
93-- | A monad transformer for small step operational semantics.
94--
95newtype StepT m α
96  = StepT
97  { runStepT ∷ MaybeT m α
98  } deriving (Monad, Functor, Applicative, Alternative)
99
100-- | To indicate that a term is in normal form.
101--
102stepsExhausted
103  ∷ Applicative m
104  ⇒ StepT m α
105stepsExhausted = StepT . MaybeT $ pure Nothing
106
107instance MonadVar Var m ⇒ MonadVar Var (StepT m) where
108  fresh = StepT . MaybeT $ Just <$> fresh
109  named str = StepT . MaybeT $ Just <$> named str
110
111-- | A single evaluation step.
112--
113step
114  ∷ Tm0 Lang
115  → StepT M (Tm0 Lang)
116step tm =
117  out tm >>= \case
118    APP :$ m :& n :& RNil →
119      out m >>= \case
120        LAM :$ xe :& RNil → xe // n
121        _ → app <$> step m <*> pure n <|> app <$> pure m <*> step n
122    PI :$ α :& xβ :& RNil → pi <$> step α <*> pure xβ
123    _ → stepsExhausted
124
125-- | The reflexive-transitive closure of a small-step operational semantics.
126--
127star
128  ∷ Monad m
129  ⇒ (α → StepT m α)
130  → (α → m α)
131star f a =
132  runMaybeT (runStepT $ f a) >>=
133    return a `maybe` star f
134
135-- | Evaluate a term to normal form
136--
137eval ∷ Tm0 Lang → Tm0 Lang
138eval = runM . star step
139
140newtype JudgeT m α
141  = JudgeT
142  { runJudgeT ∷ ExceptT String m α
143  } deriving (Monad, Functor, Applicative, Alternative)
144
145instance MonadVar Var m ⇒ MonadVar Var (JudgeT m) where
146  fresh = JudgeT . ExceptT $ Right <$> fresh
147  named str = JudgeT . ExceptT $ Right <$> named str
148
149type Ctx = [(Var, Tm0 Lang)]
150
151raise ∷ Monad m ⇒ String → JudgeT m α
152raise = JudgeT . ExceptT . return . Left
153
154checkTy
155  ∷ Ctx
156  → Tm0 Lang
157  → Tm0 Lang
158  → JudgeT M ()
159checkTy g tm ty = do
160  let ntm = eval tm
161      nty = eval ty
162  (,) <$> out ntm <*> out nty >>= \case
163    (LAM :$ xe :& RNil, PI :$ α :& yβ :& RNil) → do
164      z ← fresh
165      ez ← xe // var z
166      βz ← yβ // var z
167      checkTy ((z,α):g) ez βz
168    (AX :$ RNil, UNIT :$ RNil) → return ()
169    _ → do
170      ty'inferTy g tm
171      if ty' === nty
172        then return ()
173        else raise "Type error"
174
175inferTy
176Ctx
177Tm0 Lang
178JudgeT M (Tm0 Lang)
179inferTy g tm = do
180  out (eval tm) >>= \case
181    V v | Just (evalty) ← lookup v greturn ty
182        | otherwiseraise "Ill-scoped variable"
183    APP :$ m :& n :& RNildo
184      inferTy g m >>= out >>= \case
185        PI :$ α :&  :& RNildo
186          checkTy g n α
187          eval <$>  // n
188        _raise "Expected pi type for lambda abstraction"
189    _raise "Only infer neutral terms"
190
191-- | @λx.x@
192--
193identityTmM (Tm0 Lang)
194identityTm = do
195  xfresh
196  return $ lam (x \\ var x)
197
198-- | @(λx.x)(λx.x)@
199--
200appTmM (Tm0 Lang)
201appTm = do
202  tmidentityTm
203  return $ app tm tm
204
205-- | A demonstration of evaluating (and pretty-printing). Output:
206--
207-- @
208-- ap[lam[\@2.\@2];lam[\@3.\@3]] ~>* lam[\@4.\@4]
209-- @
210--
211mainIO ()
212main = do
213  -- Try out the type checker
214  either fail print . runM . runExceptT . runJudgeT $ do
215    xfresh
216    checkTy [] (lam (x \\ var x)) (pi unit (x \\ unit))
217
218  print . runM $ do
219    mmappTm
220    mmStrtoString mm
221    mmStr'toString $ eval mm
222    return $ mmStr ++ " ~>* " ++ mmStr'
223
224doMapFilePathIOSArrow XmlTree TiledMap
225doMap mapPath = proc mdo
226    mapWidthgetAttrR "width"m
227    returnA -< baz
228
229-- ^ An opaque ESD handle for recording data from the soundcard via ESD.
230data Recorder fr ch (r ∷ ★ → ★)
231    = Recorder {
232        reRate   ∷ !Int
233      , reHandle ∷ !Handle
234      , reCloseH ∷ !(FinalizerHandle r)
235      }
236
237-- from ghc-prim
238
239-- | A backward-compatible (pre-GHC 8.0) synonym for 'Type'
240-- type * = TYPE 'PtrRepLifted
241
242-- | A unicode backward-compatible (pre-GHC 8.0) synonym for 'Type'
243-- type ★ = TYPE 'PtrRepLifted
244