Skip to content

Instantly share code, notes, and snippets.

@fronx
Last active August 29, 2015 14:04
Show Gist options
  • Save fronx/1d34e1bebc5f090fb174 to your computer and use it in GitHub Desktop.
Save fronx/1d34e1bebc5f090fb174 to your computer and use it in GitHub Desktop.
{-# LANGUAGE FlexibleInstances #-}
module Unityped where
import Prelude hiding ((*), (==), (++), print, show, concat)
import qualified Prelude as P
import Data.List hiding ((++))
data D = B Bool
| N Int
| S String
| F ([D] -> D)
| List [D]
| Obj { typeOf :: D
, fields :: [(String, D)]
}
| Class { _name :: String
, _constr :: [D] -> [(String, D)]
}
| Method
| Null
typeCase :: D -> [(String, D)] -> D
typeCase d [] = error "empty case list"
typeCase d ((dynType, d'):more)
| (_reflect d) P.== dynType = d'
| otherwise = typeCase d more
-- access a member of an object
(.@) :: D -> String -> D
obj .@ field = member (fields obj)
where
member [] = Null
member ((key, val):more) =
if key P.== field
then val
else member more
-- create an instance of a class
new _class args =
Obj _class ((_constr _class) args)
className obj = dyn (_name (typeOf obj))
show = dyn f
where f (B True :[]) = dyn "true"
f (B False :[]) = dyn "false"
f (N n :[]) = dyn (P.show n)
f (S s :[]) = dyn s
f (F _ :[]) = dyn "(function)"
f (List l :[]) = (dyn "[") ++ showList nydShow l ++ (dyn "]")
f (obj :[]) | (Obj _class _fields) <- obj =
(className obj) ++
(dyn "{") ++
showList pairShow (fields obj) ++
(dyn "}")
showList showFn l = (dyn (intercalate ", " (map showFn l)))
nydShow d = nyd (show $$ [d])
pairShow (key, value) =
key P.++ "=" P.++ nyd (show $$ [value])
print d = putStrLn s
where S s = show $$ [d]
reflect = dyn f
where f (d:[]) = dyn (_reflect d)
_reflect (B _) = "bool"
_reflect (N _) = "number"
_reflect (S _) = "string"
_reflect (F _) = "function"
_reflect (List _) = "list"
class DynEq a where
(==) :: D -> a -> D
infix 4 ==
instance DynEq Int where
(N n) == m = dyn (n P.== m)
instance DynEq String where
(S s) == s' = dyn (s P.== s')
instance DynEq D where
(B b) == (B b') = dyn (b P.== b')
(S s) == (S s') = dyn (s P.== s')
(N n) == (N n') = dyn (n P.== n')
class Dyn a where
dyn :: a -> D
nyd :: D -> a
instance Dyn Bool where
dyn = B
nyd (B b) = b
instance Dyn Int where
dyn = N
nyd (N n) = n
instance Dyn String where
dyn = S
nyd (S s) = s
instance Dyn ([D] -> D) where
dyn = F
nyd (F f) = f
instance Dyn [D] where
dyn = List
nyd (List l) = l
dynf :: (Dyn a, Dyn b) => (a -> b) -> D -> D
dynf f d = dyn (f (nyd d))
dynf2 :: (Dyn a, Dyn b, Dyn c) => (a -> b -> c) -> D -> D -> D
dynf2 f d d' = dyn (f (nyd d) (nyd d'))
decInt = dynf f
where f :: Int -> Int
f n = n - 1
minusInt = dynf2 f
where f :: Int -> Int -> Int
f a b = a - b
mulInt = dynf2 f
where f :: Int -> Int -> Int
f = (P.*)
(++) = dynf2 f
where f :: String -> String -> String
f = (P.++)
($$) :: D -> [D] -> D
(F f) $$ ds = f ds
mul = dyn f
where
f (a:b:[]) =
if nyd (b == (1::Int))
then a
else typeCase a
[ ("number", mulInt a b)
, ("string", mul $$ [ a ++ a, decInt b ])
]
a * b = mul $$ [a, b]
person = Class "person" constr
where
constr (name:birthyear:[]) =
[ ("name", name)
, ("birthyear", birthyear)
, ("age", age)
]
where
year = N 2014
age = minusInt year birthyear
mary = new person [ dyn "Mary", N 1978 ]
joe = new person [ dyn "Joe", N 1992 ]
main = do
print (dyn True)
print (dyn False)
print (N 123)
print (dyn "hello")
print $ (dyn "2 == 3 ") ++ (show $$ [(N 2) == (N 3)])
print $ (dyn "4 == 2 * 2 ") ++ (show $$ [(N 4) == (N 2) * (N 2)])
print $ (dyn [ dyn "123", N 123, dyn [ dyn True ] ])
print show
print mary
print (mary .@ "age")
print joe
print $ (dyn "reflect(show): ") ++ (reflect $$ [show])
print $ (N 2) * (N 3)
print $ (dyn "hi") * (N 3) * (N 2)
print $ (dyn "hi") * (N 3) * (N 2) * (dyn "abc") -- "type error"
-- print $ (B True) * (N 3) -- "type error"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment