[Haskell-cafe] Interesting Thread on OO Usefulness (scala mailing
list)
Tillmann Rendel
rendel at cs.au.dk
Mon May 4 20:06:28 EDT 2009
Hi,
Paolo Losi wrote:
> I'm following an interesting thread on the scala mailing list:
>
> http://www.nabble.com/-scala--usefulness-of-OOP-td23268250.html
>
> Martin Odersky advocates the OO features of the scala language
> proposing an interesting problem where the OO approach seams
> valuable.
>
> I would be very much interested in seeing an Haskell solution
> to that problem.
Here is my take on it, using type families.
Tillmann
{-# LANGUAGE TypeFamilies #-}
import Data.List (elemIndex)
-- COMMON INTERFACE --
-- environments and variables
class Env env where
data V env
empty :: env a
bind :: (String, a) -> env a -> env a
find :: env a -> V env -> a
-- too bad we have to include these here :(
showVar :: Int -> V env -> ShowS
showEnv :: Show a => Int -> env a -> ShowS
-- GENERIC INTERPRETER --
-- terms (for some type of variables v)
data T env
= Lam [String] (T env)
| App (T env) [T env]
| Var (V env)
| Lit Integer
instance Env env => Show (T env) where
showsPrec p t = showParen (p > 10) $ case t of
Lam vs t -> ("Lam " ++) . showsPrec 11 vs . (' ' :) . showsPrec 11 t
App f xs -> ("App " ++) . showsPrec 11 f . (' ' :) . showsPrec 11 xs
Var v -> ("Var " ++) . showVar 11 v
Lit n -> ("Lit " ++) . showsPrec 11 n
-- domain of values
data D env
= Fun [String] (T env) (env (D env))
| Num Integer
instance Env env => Show (D env) where
showsPrec p t = showParen (p > 10) $ case t of
Fun vs t env -> ("Fun " ++) . showsPrec 11 vs . (' ' :) . showsPrec
11 t . (' ' :) . showEnv 11 env
Num n -> ("Num " ++) . showsPrec 11 n
-- interpreter
eval :: Env env => env (D env) -> T env -> D env
eval env (Lam vs t) = Fun vs t env
eval env (App f xs) = apply (eval env f) (map (eval env) xs)
eval env (Var v ) = find env v
eval env (Lit n ) = Num n
apply :: Env env => D env -> [D env] -> D env
apply (Fun vs t env) xs
| length vs == length xs = eval env' t
| otherwise = error ("arity mismatch: " ++ show vs ++ ", " ++ show xs)
where env' = foldr bind env (zip vs xs)
apply (Num n) xs = error "not a function"
-- VARIABLES AS STRINGS --
data AssocList a = AssocList [(String, a)] deriving Show
instance Env AssocList where
data V AssocList = Name String deriving Show
empty = AssocList []
bind (v, x) (AssocList env) = AssocList ((v, x) : env)
find (AssocList env) (Name v)
= case lookup v env of
Just x -> x
Nothing -> error "free variable"
showVar = showsPrec
showEnv = showsPrec
-- VARIABLES AS De-BRUIJN INDICES --
data Stack a = Stack [a] deriving Show
instance Env Stack where
data V Stack = Index Int deriving Show
empty = Stack []
bind (v, x) (Stack env) = Stack (x : env)
find (Stack env) (Index v)
= if v < length env
then env !! v
else error "free variable"
showVar = showsPrec
showEnv = showsPrec
-- CONVERT NAMES TO DE-BRUIJN INDICES --
index :: [String] -> T AssocList -> T Stack
index vs (Lam ws t ) = Lam ws (index (ws ++ vs) t)
index vs (App f xs ) = App (index vs f) (map (index vs) xs)
index vs (Var (Name v)) = case elemIndex v vs of
Just n -> Var (Index n)
Nothing -> error "free variable"
index vs (Lit n ) = Lit n
-- TEST --
identity = Lam ["x"] (Var (Name "x"))
two = Lam ["f", "x"] (App (Var (Name "f"))
[(App (Var (Name "f")) [(Var (Name "x"))])])
five = App two [identity, Lit 5]
test = case (eval empty five, eval empty (index [] five)) of
(Num 5, Num 5) -> True
_ -> False
More information about the Haskell-Cafe
mailing list