jl-0.1.0: src/JL/Functions.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
-- |
module JL.Functions (context, scope, functions) where
import Control.Arrow
import Data.Aeson (Value)
import Data.Function
import qualified Data.HashMap.Strict as HM
import Data.List
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as M
import Data.Maybe
import Data.Ord
import Data.Scientific
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Vector as V
import JL.Interpreter
import JL.Serializer
import JL.Types
--------------------------------------------------------------------------------
-- Lists
-- | The typing context.
context :: Map Variable Type
context = M.fromList (map (definitionName &&& definitionType) (concatMap snd functions))
-- | Bindings available in scope.
scope :: Map Variable Core
scope = M.fromList (map (definitionName &&&definitionCore) (concatMap snd functions))
-- | All functions.
functions :: [(Text, [Definition])]
functions =
[ ("Record access", [getf, setf, modifyf, keysf, elemsf])
, ( "Sequences"
, [ mapf
, filterf
, takeWhilef
, empty
, len
, rev
, dropf
, elemf
, concatf
, zipw
, takef
, foldf
, dropWhilef
, anyf
, allf
, nubf
, sortf
, appendf
, sumf
, productf
, minimumf
, maximumf
])
, ("Strings", [wordsf, unwordsf, linesf, unlinesf])
, ( "Predicate operators"
, [predicateOperator "/=" (/=), predicateOperator "=" (==)])
, ( "Boolean operators"
, [boolOperator "&&" (&&), boolOperator "||" (||), boolFun "not" not])
, ( "Numeric operators"
, [ numericPredicateOperator ">" (>)
, numericPredicateOperator "<" (<)
, numericPredicateOperator ">=" (>=)
, numericPredicateOperator "<=" (<=)
, arithmeticOperator "*" (*)
, arithmeticOperator "+" (+)
, arithmeticOperator "-" (-)
, arithmeticOperator "/" (/)
, arithmeticOperator "min" min
, arithmeticOperator "max" max
, arithmeticFun "abs" abs
])
, ("Function combinators", [idf, compose, flipf])
]
--------------------------------------------------------------------------------
-- Functions
keysf :: Definition
keysf =
Definition
{ definitionDoc = "Get all keys of the object"
, definitionName = Variable "keys"
, definitionCore =
(EvalCore
(\obj ->
case obj of
RecordCore o ->
ArrayCore
(V.fromList (map (ConstantCore . StringConstant) (HM.keys o)))
_ -> error "keys function expected an object"))
, definitionType = FunctionType JSONType JSONType
}
elemsf :: Definition
elemsf =
Definition
{ definitionDoc = "Get all elements of the object"
, definitionName = Variable "elems"
, definitionCore =
(EvalCore
(\obj ->
case obj of
RecordCore o ->
ArrayCore
(V.fromList (HM.elems o))
_ -> error "elems function expected an object"))
, definitionType = FunctionType JSONType JSONType
}
modifyf :: Definition
modifyf =
Definition
{ definitionDoc = "Modify the object at k with function f"
, definitionName = Variable "modify"
, definitionCore =
(EvalCore
(\key ->
EvalCore
(\f ->
EvalCore
(\obj ->
case (key, obj) of
(ConstantCore (StringConstant k), (RecordCore o)) ->
(RecordCore
(HM.adjust (\v -> eval (ApplicationCore f v)) k o))
_ -> error "type error for args to modify"))))
, definitionType =
FunctionType
JSONType
(FunctionType
(FunctionType JSONType JSONType)
(FunctionType JSONType JSONType))
}
getf :: Definition
getf =
Definition
{ definitionDoc = "Get the value at k from the object"
, definitionName = Variable "get"
, definitionCore =
(EvalCore
(\key ->
EvalCore
(\obj ->
case (key, obj) of
(ConstantCore (StringConstant k), RecordCore o) ->
(case HM.lookup k o of
Nothing -> error ("missing key " <> show k)
Just v -> v)
(ConstantCore (NumberConstant i), (ArrayCore v)) ->
(case v V.!? (round i) of
Nothing -> error ("missing array index " <> show i)
Just v' -> v')
_ -> error "type error for get arguments")))
, definitionType = FunctionType JSONType (FunctionType JSONType JSONType)
}
setf :: Definition
setf =
Definition
{ definitionDoc = "Set the value k to v in object"
, definitionName = Variable "set"
, definitionCore =
(EvalCore
(\key ->
EvalCore
(\val ->
EvalCore
(\obj ->
case (key, val, obj) of
(ConstantCore (StringConstant k), v, RecordCore o) ->
(RecordCore (HM.insert k v o))
_ -> error "type error in arguments to: set"))))
, definitionType =
FunctionType
JSONType
(FunctionType JSONType (FunctionType JSONType JSONType))
}
idf :: Definition
idf =
Definition
{ definitionDoc = "Identity function, returns its input unchanged"
, definitionName = Variable "id"
, definitionCore = (EvalCore (\x -> x))
, definitionType = FunctionType JSONType JSONType
}
flipf :: Definition
flipf =
Definition
{ definitionDoc = "Flips the argument order of a function of two or more arguments"
, definitionName = Variable "flip"
, definitionCore =
(EvalCore
(\f ->
EvalCore
(\x ->
EvalCore (\y -> eval (ApplicationCore (ApplicationCore f y) x)))))
, definitionType =
FunctionType
(FunctionType JSONType (FunctionType JSONType JSONType))
(FunctionType JSONType (FunctionType JSONType JSONType))
}
compose :: Definition
compose =
Definition
{ definitionDoc = "Compose two functions"
, definitionName = Variable "compose"
, definitionCore =
EvalCore
(\f ->
EvalCore
(\g ->
EvalCore (\x -> eval (ApplicationCore g (ApplicationCore f x)))))
, definitionType =
FunctionType
(FunctionType JSONType JSONType)
(FunctionType
(FunctionType JSONType JSONType)
(FunctionType JSONType JSONType))
}
foldf :: Definition
foldf =
Definition
{ definitionDoc = "Fold over a structure with a state."
, definitionName = Variable "fold"
, definitionCore =
EvalCore
(\cons ->
EvalCore
(\nil ->
EvalCore
(\xs ->
case xs of
ArrayCore xs' ->
(V.foldl
(\acc x ->
eval
(ApplicationCore (ApplicationCore cons acc) x))
nil
xs')
ConstantCore (StringConstant xs') ->
(T.foldl
(\acc x ->
eval
(ApplicationCore
(ApplicationCore cons acc)
(ConstantCore
(StringConstant (T.singleton x)))))
nil
xs')
_ -> error "can only fold sequences")))
, definitionType =
(FunctionType
((FunctionType JSONType (FunctionType JSONType JSONType)))
(FunctionType JSONType (FunctionType JSONType JSONType)))
}
zipw :: Definition
zipw =
Definition
{ definitionDoc = "Zip two lists calling with each element to f x y"
, definitionName = Variable "zipWith"
, definitionCore =
EvalCore
(\f ->
EvalCore
(\xs ->
EvalCore
(\ys ->
case (xs, ys) of
(ArrayCore xs', ArrayCore ys') ->
(ArrayCore
(V.zipWith
(\x y ->
eval (ApplicationCore (ApplicationCore f x) y))
xs'
ys'))
_ -> error "can only zip two arrays")))
, definitionType =
FunctionType
(FunctionType JSONType (FunctionType JSONType JSONType))
(FunctionType JSONType (FunctionType JSONType JSONType))
}
elemf :: Definition
elemf =
Definition
{ definitionDoc = "Is x an element of y?"
, definitionName = Variable "elem"
, definitionCore =
EvalCore
(\n ->
EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ConstantCore
(BoolConstant
(V.elem (coreToValue n) (fmap coreToValue xs'))))
(ConstantCore (StringConstant xs')) ->
(ConstantCore
(BoolConstant
(isJust
(T.findIndex
(\cc ->
case n of
ConstantCore (StringConstant c) ->
c == T.singleton cc
_ -> False)
xs'))))
_ ->
error
"can only check elements from sequences"))
, definitionType = FunctionType JSONType (FunctionType JSONType JSONType)
}
takef :: Definition
takef =
Definition
{ definitionDoc = "Take n items from sequence"
, definitionName = Variable "take"
, definitionCore =
EvalCore
(\n ->
EvalCore
(\xs ->
case (n, xs) of
(ConstantCore (NumberConstant n'), ArrayCore xs') ->
(ArrayCore (V.take (round n') xs'))
(ConstantCore (NumberConstant n'), ConstantCore (StringConstant xs')) ->
(ConstantCore (StringConstant (T.take (round n') xs')))
_ -> error "can only take from sequences"))
, definitionType = FunctionType JSONType (FunctionType JSONType JSONType)
}
dropf :: Definition
dropf =
Definition
{ definitionDoc = "Drop n items from the sequence"
, definitionName = Variable "drop"
, definitionCore =
EvalCore
(\n ->
EvalCore
(\xs ->
case (n, xs) of
(ConstantCore (NumberConstant n'), ConstantCore (StringConstant xs')) ->
(ConstantCore (StringConstant (T.drop (round n') xs')))
(ConstantCore (NumberConstant n'), ArrayCore xs') ->
(ArrayCore (V.drop (round n') xs'))
_ -> error "can only drop from sequences"))
, definitionType = FunctionType JSONType (FunctionType JSONType JSONType)
}
concatf :: Definition
concatf =
Definition
{ definitionDoc = "Concatenate a list of sequences into one sequence"
, definitionName = Variable "concat"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ArrayCore (V.concat (map coreToArray (V.toList xs'))))
_ -> error "can only concat arrays"))
, definitionType = FunctionType JSONType JSONType
}
rev :: Definition
rev =
Definition
{ definitionDoc = "Reverse a sequence"
, definitionName = Variable "reverse"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ArrayCore xs') -> (ArrayCore (V.reverse xs'))
(ConstantCore (StringConstant xs')) ->
(ConstantCore (StringConstant (T.reverse xs')))
_ -> error "can only reverse a sequence"))
, definitionType = FunctionType JSONType JSONType
}
appendf :: Definition
appendf =
Definition
{ definitionDoc = "Append the members of the second sequence to the first sequence"
, definitionName = Variable "append"
, definitionCore =
(EvalCore
(\xs ->
(EvalCore
(\ys ->
case (xs, ys) of
(ArrayCore xs', ArrayCore ys') -> (ArrayCore (xs' <> ys'))
(ConstantCore (StringConstant xs'), ConstantCore (StringConstant ys')) ->
(ConstantCore (StringConstant (xs' <> ys')))
_ -> error "can only append two sequences of the same type"))))
, definitionType = FunctionType JSONType (FunctionType JSONType JSONType)
}
nubf :: Definition
nubf =
Definition
{ definitionDoc = "Return the sequence with no duplicates; the nub of it"
, definitionName = Variable "nub"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ArrayCore
(V.fromList (nubBy (on (==) coreToValue) (V.toList xs'))))
(ConstantCore (StringConstant xs')) ->
(ConstantCore
(StringConstant
(T.pack (nub (T.unpack xs')))))
_ -> error "can only nub a sequence"))
, definitionType = FunctionType JSONType JSONType
}
linesf :: Definition
linesf =
Definition
{ definitionDoc = "Split the string into a list of lines"
, definitionName = Variable "lines"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ConstantCore (StringConstant xs')) ->
(ArrayCore
(V.map
(ConstantCore . StringConstant)
((V.fromList (T.lines xs')))))
_ -> error "can only lines a string"))
, definitionType = FunctionType JSONType JSONType
}
wordsf :: Definition
wordsf =
Definition
{ definitionDoc = "Split the string into a list of words"
, definitionName = Variable "words"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ConstantCore (StringConstant xs')) ->
(ArrayCore
(V.map
(ConstantCore . StringConstant)
((V.fromList (T.words xs')))))
_ -> error "can only words a string"))
, definitionType = FunctionType JSONType JSONType
}
unwordsf :: Definition
unwordsf =
Definition
{ definitionDoc = "Join the list of strings into a string separated by spaces"
, definitionName = Variable "unwords"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ConstantCore (StringConstant (T.unwords (V.toList (fmap coreToString xs')))))
_ -> error "can only unwords a string"))
, definitionType = FunctionType JSONType JSONType
}
unlinesf :: Definition
unlinesf =
Definition
{ definitionDoc = "Join the list of strings into a string separated by lines and terminated by a new line"
, definitionName = Variable "unlines"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ConstantCore (StringConstant (T.unlines (V.toList (fmap coreToString xs')))))
_ -> error "can only unlines a string"))
, definitionType = FunctionType JSONType JSONType
}
sortf :: Definition
sortf =
Definition
{ definitionDoc = "Return the sequence sorted"
, definitionName = Variable "sort"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ArrayCore
(V.fromList (sortBy (comparing coreToCompare) (V.toList xs'))))
(ConstantCore (StringConstant xs')) ->
(ConstantCore
(StringConstant
(T.pack (sort (T.unpack xs')))))
_ -> error "can only sort a sequence"))
, definitionType = FunctionType JSONType JSONType
}
len :: Definition
len =
Definition
{ definitionDoc = "Get the length of a sequence"
, definitionName = Variable "length"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ConstantCore (NumberConstant (fromIntegral (V.length xs'))))
(ConstantCore (StringConstant xs')) ->
(ConstantCore (NumberConstant (fromIntegral (T.length xs'))))
_ -> error "can only take length of sequences"))
, definitionType = FunctionType JSONType JSONType
}
sumf :: Definition
sumf =
Definition
{ definitionDoc = "Get the sum of a sequence"
, definitionName = Variable "sum"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ConstantCore (NumberConstant (V.sum (fmap coreToNumber xs'))))
_ -> error "can only take sum of arrays"))
, definitionType = FunctionType JSONType JSONType
}
productf :: Definition
productf =
Definition
{ definitionDoc = "Get the product of a sequence"
, definitionName = Variable "product"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ConstantCore (NumberConstant (V.product (fmap coreToNumber xs'))))
_ -> error "can only take product of arrays"))
, definitionType = FunctionType JSONType JSONType
}
maximumf :: Definition
maximumf =
Definition
{ definitionDoc = "Get the maximum of a sequence"
, definitionName = Variable "maximum"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ConstantCore (NumberConstant (V.maximum (fmap coreToNumber xs'))))
_ -> error "can only take maximum of arrays"))
, definitionType = FunctionType JSONType JSONType
}
minimumf :: Definition
minimumf =
Definition
{ definitionDoc = "Get the minimum of a sequence"
, definitionName = Variable "minimum"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ConstantCore (NumberConstant (V.minimum (fmap coreToNumber xs'))))
_ -> error "can only take minimum of arrays"))
, definitionType = FunctionType JSONType JSONType
}
empty :: Definition
empty =
Definition
{ definitionDoc = "Is a sequence empty?"
, definitionName = Variable "empty"
, definitionCore =
(EvalCore
(\xs ->
case xs of
(ArrayCore xs') -> (ConstantCore (BoolConstant (V.null xs')))
(ConstantCore (StringConstant xs')) ->
(ConstantCore (BoolConstant (T.null xs')))
_ -> error "can only check if sequences are empty"))
, definitionType = FunctionType JSONType JSONType
}
anyf :: Definition
anyf =
Definition
{ definitionDoc = "Does p return true for any of the elements?"
, definitionName = Variable "any"
, definitionCore =
EvalCore
(\f ->
EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ConstantCore
(BoolConstant
(V.any
(\x ->
case eval (ApplicationCore f x) of
ConstantCore (BoolConstant b) -> b
_ -> True)
xs')))
(ConstantCore (StringConstant xs')) ->
(ConstantCore
(BoolConstant
(T.any
(\x ->
case eval
(ApplicationCore
f
(ConstantCore
(StringConstant (T.singleton x)))) of
ConstantCore (BoolConstant b) -> b
_ -> True)
xs')))
_ -> error "can only any over sequences"))
, definitionType =
FunctionType
(FunctionType JSONType JSONType)
(FunctionType JSONType JSONType)
}
allf :: Definition
allf =
Definition
{ definitionDoc = "Does p return true for all of the elements?"
, definitionName = Variable "all"
, definitionCore =
EvalCore
(\f ->
EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ConstantCore
(BoolConstant
(V.all
(\x ->
case eval (ApplicationCore f x) of
ConstantCore (BoolConstant b) -> b
_ -> True)
xs')))
(ConstantCore (StringConstant xs')) ->
(ConstantCore
(BoolConstant
(T.all
(\x ->
case eval
(ApplicationCore
f
(ConstantCore
(StringConstant (T.singleton x)))) of
ConstantCore (BoolConstant b) -> b
_ -> True)
xs')))
_ -> error "can only all over sequences"))
, definitionType =
FunctionType
(FunctionType JSONType JSONType)
(FunctionType JSONType JSONType)
}
dropWhilef :: Definition
dropWhilef =
Definition
{ definitionDoc = "Drop elements from a sequence while a predicate is true"
, definitionName = Variable "dropWhile"
, definitionCore =
EvalCore
(\f ->
EvalCore
(\xs ->
case xs of
(ArrayCore xs') ->
(ArrayCore
(V.dropWhile
(\x ->
case eval (ApplicationCore f x) of
ConstantCore (BoolConstant b) -> b
_ -> True)
xs'))
(ConstantCore (StringConstant xs')) ->
(ConstantCore
(StringConstant
(T.dropWhile
(\x ->
case eval
(ApplicationCore
f
(ConstantCore
(StringConstant (T.singleton x)))) of
ConstantCore (BoolConstant b) -> b
_ -> True)
xs')))
_ -> error "can only dropWhile over sequences"))
, definitionType =
FunctionType
(FunctionType JSONType JSONType)
(FunctionType JSONType JSONType)
}
takeWhilef :: Definition
takeWhilef =
Definition
{ definitionDoc =
"Take elements from a sequence while given predicate is true"
, definitionName = Variable "takeWhile"
, definitionCore =
(EvalCore
(\f ->
EvalCore
(\xs ->
case xs of
(ConstantCore (StringConstant xs')) ->
(ConstantCore
(StringConstant
(T.takeWhile
(\x ->
case eval
(ApplicationCore
f
(ConstantCore
(StringConstant (T.singleton x)))) of
ConstantCore (BoolConstant b) -> b
_ -> True)
xs')))
(ArrayCore xs') ->
(ArrayCore
(V.takeWhile
(\x ->
case eval (ApplicationCore f x) of
ConstantCore (BoolConstant b) -> b
_ -> True)
xs'))
_ -> error "can only takeWhile over sequences")))
, definitionType =
FunctionType
(FunctionType JSONType JSONType)
(FunctionType JSONType JSONType)
}
filterf :: Definition
filterf =
Definition
{ definitionDoc = "Keep only items from the sequence for which p returns true"
, definitionName = Variable "filter"
, definitionCore =
EvalCore
(\f ->
EvalCore
(\xs ->
case xs of
(ConstantCore (StringConstant xs')) ->
(ConstantCore
(StringConstant
(T.filter
(\x ->
case eval
(ApplicationCore
f
(ConstantCore
(StringConstant (T.singleton x)))) of
ConstantCore (BoolConstant b) -> b
_ -> True)
xs')))
(ArrayCore xs') ->
(ArrayCore
(V.filter
(\x ->
case eval (ApplicationCore f x) of
ConstantCore (BoolConstant b) -> b
_ -> True)
xs'))
_ -> error "can only filter over sequences"))
, definitionType =
FunctionType
(FunctionType JSONType JSONType)
(FunctionType JSONType JSONType)
}
mapf :: Definition
mapf =
Definition
{ definitionDoc = "Apply a function to every element in the sequence"
, definitionName = Variable "map"
, definitionCore =
EvalCore
(\f ->
EvalCore
(\xs ->
case xs of
(ConstantCore (StringConstant xs')) ->
(ConstantCore
(StringConstant
(T.concatMap
(\x ->
case eval
(ApplicationCore
f
(ConstantCore
(StringConstant (T.singleton x)))) of
ConstantCore (StringConstant b) -> b
_ -> error "map over a string must return strings")
xs')))
(ArrayCore xs') ->
(ArrayCore (fmap (\x -> (eval (ApplicationCore f (x)))) xs'))
_ -> error "can only map over sequences"))
, definitionType =
FunctionType
(FunctionType JSONType JSONType)
(FunctionType JSONType JSONType)
}
--------------------------------------------------------------------------------
-- Function builders
arithmeticOperator :: Text -> (Scientific -> Scientific -> Scientific) -> Definition
arithmeticOperator name f =
Definition
{ definitionName = Variable name
, definitionCore =
EvalCore
(\x ->
EvalCore
(\y ->
case (x, y) of
(ConstantCore (NumberConstant a), ConstantCore (NumberConstant b)) ->
ConstantCore (NumberConstant (f a b))
_ -> error ("type error for arguments to " <> show name)))
, definitionType = JSONType .-> JSONType .-> JSONType
, definitionDoc = "a " <> name <> " b"
}
boolOperator :: Text -> (Bool -> Bool -> Bool) -> Definition
boolOperator name f =
Definition
{ definitionName = Variable name
, definitionCore =
EvalCore
(\x ->
EvalCore
(\y ->
case (x, y) of
(ConstantCore (BoolConstant a), ConstantCore (BoolConstant b)) ->
ConstantCore (BoolConstant (f a b))
_ -> error ("type error for arguments to " <> show name)))
, definitionType = JSONType .-> JSONType .-> JSONType
, definitionDoc = "a " <> name <> " b"
}
arithmeticFun :: Text -> (Scientific -> Scientific) -> Definition
arithmeticFun name f =
Definition
{ definitionName = Variable name
, definitionCore =
EvalCore
(\x ->
case (x) of
(ConstantCore (NumberConstant a)) ->
ConstantCore (NumberConstant (f a))
_ -> error ("type error for arguments to " <> show name))
, definitionType = JSONType .-> JSONType
, definitionDoc = name <> " b"
}
boolFun :: Text -> (Bool -> Bool) -> Definition
boolFun name f =
Definition
{ definitionName = Variable name
, definitionCore =
EvalCore
(\x ->
case (x) of
(ConstantCore (BoolConstant a)) ->
ConstantCore (BoolConstant (f a))
_ -> error ("type error for arguments to " <> show name))
, definitionType = JSONType .-> JSONType
, definitionDoc = name <> " b"
}
predicateOperator :: Text -> (Value -> Value -> Bool) -> Definition
predicateOperator name f =
Definition
{ definitionName = Variable name
, definitionCore =
EvalCore
(\x ->
EvalCore
(\y ->
ConstantCore (BoolConstant (f (coreToValue x) (coreToValue y)))))
, definitionType = JSONType .-> JSONType .-> JSONType
, definitionDoc = "a " <> name <> " b"
}
numericPredicateOperator :: Text -> (Scientific -> Scientific -> Bool) -> Definition
numericPredicateOperator name f =
Definition
{ definitionName = Variable name
, definitionCore =
EvalCore
(\x ->
EvalCore
(\y ->
case (x, y) of
(ConstantCore (NumberConstant a), ConstantCore (NumberConstant b)) ->
ConstantCore (BoolConstant (f a b))
_ -> error ("type error for arguments to " <> show name)))
, definitionType = JSONType .-> JSONType .-> JSONType
, definitionDoc = "a " <> name <> " b"
}
--------------------------------------------------------------------------------
-- Handy combinators
-- | Type a -> b.
(.->) :: Type -> Type -> Type
a .-> b = FunctionType a b
infixr 9 .->