technique-0.2.5: lib/Technique/Internal.hs
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
-- I generally try to avoid modules full of (only) types but these are here
-- so the can be shared in both Technique.Translate and Technique.Builtins.
-- |
-- Builing blocks for the translation stage of the compiler.
module Technique.Internal where
import Core.Text
import Data.DList
import Technique.Language
import Technique.Quantity
-- FIXME ??? upgrade to named IVar
newtype Promise = Promise Value
-- |
-- The resolved value of eiter a literal or function applicaiton, either as
-- that literal, the expression, or as the result of waiting on the variable
-- it was assigned to.
--
-- Need names? Science names newly discovered creatures in Latin. I don't
-- speak Latin, but neither does anyone else so we can just make words up.
-- Yeay! (The lengths some people will go to in order to avoid qualified
-- imports is really impressive, isn't it?)
data Value
= Unitus
| Literali Rope
| Quanticle Quantity
| Tabularum [(Rope, Value)]
| Parametriq [Value]
deriving (Eq, Show)
-- |
-- The internal representation of a Procedure, with ambiguities resolved.
--
-- We landed on Subroutine as the name of translated user-defined Procedure.
--
-- Procedures which are actually fundamental [in the context of the domain
-- specific language] represented by builtin IO actions which we call
-- Primatives.
--
-- The first constructor, Unresolved, is for the first stage pass through the
-- translate phase when we are still accumulating definitions, thereby
-- allowing for the forward use of not-yet-defiend procedures that will be
-- encountered in the same scope.
-- Didn't want to call this "function" because that means something in
-- functional programming and in programming language theory and this isn't
-- it. Other alternatives considered include Instance (the original name,
-- but we've reserved that to be used when instantiating a procedure at
-- runtime), Representation, and Internal. Subroutine is ok.
data Function
= Unresolved Identifier
| Subroutine Procedure Step
| Primitive Procedure (Step -> IO Value)
functionName :: Function -> Identifier
functionName func = case func of
Unresolved name -> name
Subroutine proc _ -> procedureName proc
Primitive prim _ -> procedureName prim
instance Show Function where
show func =
let name = fromRope (unIdentifier (functionName func))
in case func of
Unresolved _ -> "Unresolved \"" ++ name ++ "\""
Subroutine _ step -> "Subroutine \"" ++ name ++ "\": " ++ show step
Primitive _ _ -> "Primitive \"" ++ name ++ "\""
instance Eq Function where
(==) f1 f2 = case f1 of
Unresolved i1 -> case f2 of
Unresolved i2 -> i1 == i2
_ -> False
Subroutine proc1 step1 -> case f2 of
Subroutine proc2 step2 -> proc1 == proc2 && step1 == step2
_ -> False
-- this is weak, but we can't compare Haskell functions for equality so if
-- the Procedures are the same then we assume the Primitives are.
Primitive proc1 _ -> case f2 of
Primitive proc2 _ -> proc1 == proc2
_ -> False
newtype Name = Name Rope -- ??? upgrade to named IVar := Promise ???
deriving (Eq, Show)
-- |
-- Names. Always needing names. These ones are from original work when we
-- envisioned technique as a shallow embedding of a domain specific
-- language implemented in Haskell. Comments describing constructors are
-- taken from a suggestion by Oleg Kiselyov on page 23 of his course "Typed
-- Tagless Final Interpreters" that the constructors of a simply typed
-- lambda calculus in this style could be considered a "minimal
-- intuitionistic logic" which is absolutely fabulous.
-- While it probably would work to put an Asynchronous into a Tuple list,
-- it's not valid from the point of view of the surface language syntax.
data Step
= Known Offset Value -- literals ("axioms")
| Bench Offset [(Label, Step)]
| Depends Offset Name -- block waiting on a value ("reference to a hypothesis denoted by a variable")
| NoOp
| Tuple Offset [Step]
| Asynchronous Offset [Name] Step -- assignment (ie lambda, "implication introduction"
| Invocation Offset Attribute Function Step -- function application ("implication elimination") on a [sub] Procedure
| Nested Offset (DList Step)
-- assumption axiom?
-- weakening?
deriving (Eq, Show)
instance Located Step where
locationOf step = case step of
Known o _ -> o
Bench o _ -> o
Depends o _ -> o
NoOp -> -2
Tuple o _ -> o
Asynchronous o _ _ -> o
Invocation o _ _ _ -> o
Nested o _ -> o
instance Semigroup Step where
(<>) = mappend
instance Monoid Step where
mempty = NoOp
mappend NoOp s2 = s2
mappend s1 NoOp = s1
mappend (Nested o1 list1) (Nested _ list2) = Nested o1 (append list1 list2)
mappend (Nested o1 list1) s2 = Nested o1 (snoc list1 s2)
mappend s1 (Nested _ list2) = Nested (locationOf s1) (cons s1 list2)
mappend s1 s2 = Nested (locationOf s1) (snoc (singleton s1) s2)