I am creating a tiny language in Haskell that can perform simple math equations. The set up looks like this:
data E = IntLit Int
| BoolLit Bool
| Plus E E
| Minus E E
| Multiplies E E
| Exponentiate E E
| Equals E E
deriving (Eq, Show)
I have all of these working, but now I need to define a function for E that preserves the truth value of the expression by taking logs to base 2 if it is possible. If it isn't possible, the program may abort (e.g., with a Non-exhaustive pattern exception).
log2Sim :: E -> E
An example of running this should look like
> log2Sim (IntLit 8)
IntLit 3
Do I need to add log2Sim E to the language defined or is there another way? I'm trying to define it like so:
log2Sim :: E -> E
log2Sim (Log a) = log2sim (eval a)
log2sim (IntLit x) = IntLit $ logBase 2 x
But this is definitely not correct.
Let's always eval to see if we get an IntLit
Something like (not typechecked...)
log2Sim :: E -> E
log2sim x = case (eval x) of
IntLit i -> IntLit (logBase 2 i)
x1 -> error $ "type error: can't take the log of a non-IntLit-valued expression: " ++ show x1
Related
Im trying to implement a Binary Tree Search algorithm in haskell.
data BinTree k d =
Branch (BinTree k d) (BinTree k d) k d
| Leaf k d
| Empty
deriving (Eq, Show)
is the data structure im using to capture my binary tree. The problem is I dont know what to return if we cant find the value. This is what I have so far for my search function :
lkp :: (Monad m, Ord k) => BinTree k d -> k -> m d
lkp (Leaf a b) x
| a == x = return(b)
lkp (Branch lSub rSub a b) x
| a < x = lkp rSub x
| a > x = lkp lSub x
| a == x = return(b)
I can see in the tests that the test expects a return value of [] back yet I cannot understand how we return this empty value. This is an example of one of those tests :
testCase "3 in Leaf 5 500 ([]))[1 mark]"
(lkp (Leaf 5 500) 3 #?= [] )
So we miss a way to return a “zero” or “empty” value.
Fortunately, the Haskell base library (Prelude) offers the MonadPlus class. MonadPlus is a specialized version of Monad, which augments the regular Monad interface with mzero and mplus, providing essentially a monoid-like structure. Theory here on the Haskell Wiki.
Using MonadPlus, the code for lkp can be written as follows:
import Control.Monad
data BinTree k d =
Branch (BinTree k d) (BinTree k d) k d
| Leaf k d
| Empty
deriving (Eq, Show)
lkp :: (MonadPlus m, Ord k) => BinTree k d -> k -> m d
lkp (Branch lSub rSub a b) x
| a < x = lkp rSub x
| a > x = lkp lSub x
| otherwise = return b
lkp (Leaf a b) x = if (a == x) then (return b) else mzero
lkp Empty _ = mzero
Note:: I am using the otherwise keyword instead of the equality test in order to silence a spurious “non-exhaustive patterns” warning.
Testing under ghci:
λ>
λ> :load q65169028.hs
[1 of 1] Compiling Main ( q65169028.hs, interpreted )
Ok, one module loaded.
λ>
λ> tr1 = Branch (Leaf 1 2) (Branch (Leaf 5 6) (Branch (Leaf 9 10) (Leaf 17 18) 13 14) 7 8) 3 4
λ>
λ> (lkp tr1 7) :: [Int]
[8]
λ>
λ> (lkp tr1 8) :: [Int]
[]
λ>
λ> (lkp tr1 17) :: [Int]
[18]
λ>
We want to force the interpreter to choose lists as our MonadPlus instance, hence the :: [Int] type signature at the end of each line.
If that sounds too cumbersome, it is always possible the specialize the lkp function further, like this:
llkp :: Ord k => BinTree k d -> k -> [d]
llkp tr x = lkp tr x
Hi I need help with calculating a type. The whole program is suppose to take a string, parse it, and at the end, calculate a value. The string I start with can be like this: "let X = + 1 2 in * X 2 - X". When I parse it, I will get this: "Let (Vari X) (Sum (Lit 1) (Lit 2)) (Mul (Vari X) (Lit 2)))". At this moment, I can parse expressions like this "* + 2 3 * 2 + 6 - 2" and the previous. But I can not calculate the previous expression, "let X = + 1 2 in * X 2 - X". If someone could point me in the the right direction I would be happy, cause right now, I really don't know how I would make this work. Thanks
Code:
data Chara = A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z deriving (Eq, Show)
data Number = Single Int | Many Int Number deriving (Eq, Show)
data Expr = Lit Int | Sub Expr | Sum Expr Expr | Mul Expr Expr | Vari Chara | Let Expr Expr Expr
deriving Show
--Want to calculate this
--Let (Vari X) (Sum (Lit 1) (Lit 2)) (Mul (Vari X) (Lit 2)))
calculate :: Expr -> Int
calculate (Sub a) = let e = calculate a in (-e)
calculate (Sum a b) = let e = calculate a
r = calculate b
in (e+r)
calculate (Mul a b) = let e = calculate a
r = calculate b
in (e*r)
calculate (Lit a) = a
You'll need to perform variable substitution in your AST. I.e. you need a function
substitute :: (Chara, Expr) -> Expr -> Expr
which, given a pair of variable to substitute and expression to substitute it with will traverse the tree and perform that substitution. That basically means: if you find a Vari, just replace it with the substitution. If you find anything with subexpressions like Sum a b, recurse down into those subexpressions and then rebuild the operator with the results, i.e.
Sum (substitute s a) (substitute s b)
Then the calculate (Let var subst expr) = ... is a pretty straightforward invocation of the substitute function.
Works like a charm
calculate :: Expr -> Int
calculate (Sub a) = let e = calculate a in (-e)
calculate (Sum a b) = let e = calculate a
r = calculate b
in (e+r)
calculate (Mul a b) = let e = calculate a
r = calculate b
in (e*r)
calculate (Let a b c) = calculate (substitute (getCharaFromExpr a) b c)
calculate (Lit a) = a
substitute :: Chara -> Expr -> Expr -> Expr
substitute x y (Lit a) = Lit a
substitute x y (Vari a) | x == a = y
| otherwise = Vari a
substitute x y (Sum a b) = Sum (substitute x y a) (substitute x y b)
substitute x y (Mul a b) = Mul (substitute x y a) (substitute x y b)
substitute x y (Sub a) = Sub (substitute x y a)
substitute x y (Let a b c) = Let (substitute x y a) (substitute x y b) (substitute x y c)
i am making tiny language. Let E be a tiny programming language that supports the declaration of arithmetic expressions and equality comparison on integers.
given the following data type E:
data E = IntLit Int
| BoolLit Bool
| Plus E E
| Minus E E
| Multiplies E E
| Exponentiate E E
| Equals E E
deriving (Eq, Show)
here is my code with above data it is working all of these.
data E = IntLit Int
| BoolLit Bool
| Plus E E
| Minus E E
| Multiplies E E
| Divides E E
| Equals E E
| log2Sim E E
deriving (Eq, Show)
eval :: E -> E
eval c#(IntLit i) = c
eval c#(BoolLit b) = c
eval (Plus a b) = plus (eval a) (eval b)
eval (Minus a b) = minus (eval a) (eval b)
eval (Multiplies a b) = multiplies (eval a) (eval b)
eval (Divides a b) = divides (eval a) (eval b)
eval (Equals a b) = equals (eval a) (eval b)
log2Sim :: E -> E
log2sim = case (eval x) of
IntLit i -> IntLit (logBase 2 i)
x1 -> "type error: can't take the log of a non-IntLit-valued expresstio" ++ show x1
plus (IntLit i) (IntLit j) = IntLit $ i + j
plus _ _ = error "Type error in addition"
minus (IntLit i) (IntLit j) = IntLit $ i - j
minus _ _ = error "Type error in subtraction"
multiplies (IntLit i) (IntLit j) = IntLit $ i * j
multiplies _ _ = error "Type error in multiplication"
divides (IntLit i) (IntLit j) = IntLit $ i `div` j
divides _ _ = error "Type error in division"
equals (IntLit i) (IntLit j) = BoolLit $ i == j
equals (BoolLit a) (BoolLit b) = BoolLit $ a == b
equals _ _ = error "Type error in equals"
when i compiled it, there are some errors.
what error is this?
A3.hs:56:7:
Couldn't match expected type `E' against inferred type `[Char]'
In the expression:
"type error: can't take the lof of a non-IntLit-valued expression: "
++
show x1
In a case alternative:
x1
-> "type error: can't take the lof of a non-IntLit-valued expression: "
++
show x1
In the expression:
case (eval x) of
IntLit i -> IntLit (logBase 2 i)
x1
-> "type error: can't take the lof of a non-IntLit-valued expression: "
++
show x1
There are many problems in your code:
All constructors must start with an upper-case letter. So data E = ... | log2Sim E E is incorrect. You also probably just want one E, hence for example data E = ... | Log E would fix both these problems.
You declared log2Sim but defined log2sim (notice the difference in capitalization). You also forgot to write the argument x to the left of the = in the definition. Fix both problems by writing
log2Sim x = ...
Strings are not valid expressions of type E. You probably wanted to follow the pattern in the rest of your code by calling error to turn your error string into an E. Thus:
x1 -> error $ "type error: can't take the log of a non-IntLit-valued expresstio" ++ show x1
logBase operates on Floating-point numbers, and Int is not one. There's a few ways to fix this, but the shortest distance between here and there is to convert to a Double and back. For example:
IntLit i -> IntLit . floor . logBase 2 . fromIntegral $ i
This is enough to make your code compile, though there may be other problems.
I am trying to print out the contents of a column matrix in Haskell:
data Vector n e where
Nil :: Vector Zero e
(:>) :: e -> Vector n e -> Vector (Succ n) e
infixr :>
data Matrix r c e where
ColMatrix :: Vector r e -> Matrix r One e
(:|) :: Vector r e -> Matrix r c e -> Matrix r (Succ c) e
infixr :|
instance Show e => Show (Matrix r c e) where
show (ColMatrix v) = -- ...
show (v :| m) = -- ...
I'm not sure how to implement this, though. The logical progression is to go
1 4 7
2 5 8
3 6 9
but printing to the terminal doesn't make this especially easy.
How do I implement this instance of Show for a ColMatrix?
You might want to consider something like Brent Yorgey's boxes package, whose maintenance I recently took over. Use text to put each number in a box, use // to build the columns, and then use <+> to put the columns together into a matrix. Then render the result. You can use cols to compare the widths of the columns before pasting them together so you can pad them all to the same width, if you like.
Please note that Show is not for pretty printing. It is intended for human-readable serialization to a Haskell-like format.
Here is a solution that uses ordinary lists and list library functions.
toList :: Vector n e -> [e]
toList Nil = []
toList (a :> v) = a : toList v
instance Show e => Show (Matrix r c e) where
show (ColMatrix v) = concat $ intersperse " " (map show (toList v))
show (v :| m) = show (ColMatrix v) ++ "\n" ++ show m
Suppose there are some data types to express lambda and combinatorial terms:
data Lam α = Var α -- v
| Abs α (Lam α) -- λv . e1
| App (Lam α) (Lam α) -- e1 e2
deriving (Eq, Show)
infixl 0 :#
data SKI α = V α -- x
| SKI α :# SKI α -- e1 e2
| I -- I
| K -- K
| S -- S
deriving (Eq, Show)
There is also a function to get a list of lambda term's free variables:
fv ∷ Eq α ⇒ Lam α → [α]
fv (Var v) = [v]
fv (Abs x e) = filter (/= x) $ fv e
fv (App e1 e2) = fv e1 ++ fv e2
To convert lambda term to combinatorial term abstract elimination rules could be usefull:
convert ∷ Eq α ⇒ Lam α → SKI α
1) T[x] => x
convert (Var x) = V x
2) T[(E₁ E₂)] => (T[E₁] T[E₂])
convert (App e1 e2) = (convert e1) :# (convert e2)
3) T[λx.E] => (K T[E]) (if x does not occur free in E)
convert (Abs x e) | x `notElem` fv e = K :# (convert e)
4) T[λx.x] => I
convert (Abs x (Var y)) = if x == y then I else K :# V y
5) T[λx.λy.E] => T[λx.T[λy.E]] (if x occurs free in E)
convert (Abs x (Abs y e)) | x `elem` fv e = convert (Abs x (convert (Abs y e)))
6) T[λx.(E₁ E₂)] => (S T[λx.E₁] T[λx.E₂])
convert (Abs x (App y z)) = S :# (convert (Abs x y)) :# (convert (Abs x z))
convert _ = error ":["
This definition is not valid because of 5):
Couldn't match expected type `Lam α' with actual type `SKI α'
In the return type of a call of `convert'
In the second argument of `Abs', namely `(convert (Abs y e))'
In the first argument of `convert', namely
`(Abs x (convert (Abs y e)))'
So, what I have now is:
> convert $ Abs "x" $ Abs "y" $ App (Var "y") (Var "x")
*** Exception: :[
What I want is (hope I calculate it right):
> convert $ Abs "x" $ Abs "y" $ App (Var "y") (Var "x")
S :# (S (KS) (S (KK) I)) (S (KK) I)
Question:
If lambda term and combinatorial term have a different types of expression, how 5) could be formulated right?
Let's consider the equation T[λx.λy.E] => T[λx.T[λy.E]].
We know the result of T[λy.E] is an SKI expression. Since it has been produced by one of the cases 3, 4 or 6, it is either I or an application (:#).
Thus the outer T in T[λx.T[λy.E]] must be one of the cases 3 or 6. You can perform this case analysis in the code. I'm sorry but I don't have the time to write it out.
Here it's better to have a common data type for combinators and lambda expressions. Notice that your types already have significant overlap (Var, App), and it doesn't hurt to have combinators in lambda expressions.
The only possibility we want to eliminate is having lambda abstractions in combinator terms. We can forbid them using indexed types.
In the following code the type of a term is parameterised by the number of nested lambda abstractions in that term. The convert function returns Term Z a, where Z means zero, so there are no lambda abstractions in the returned term.
For more information about singleton types (which are used a bit here), see the paper Dependently Typed Programming with Singletons.
{-# LANGUAGE DataKinds, KindSignatures, TypeFamilies, GADTs, TypeOperators,
ScopedTypeVariables, MultiParamTypeClasses, FlexibleInstances #-}
data Nat = Z | Inc Nat
data SNat :: Nat -> * where
SZ :: SNat Z
SInc :: NatSingleton n => SNat n -> SNat (Inc n)
class NatSingleton (a :: Nat) where
sing :: SNat a
instance NatSingleton Z where sing = SZ
instance NatSingleton a => NatSingleton (Inc a) where sing = SInc sing
type family Max (a :: Nat) (b :: Nat) :: Nat
type instance Max Z a = a
type instance Max a Z = a
type instance Max (Inc a) (Inc b) = Inc (Max a b)
data Term (l :: Nat) a where
Var :: a -> Term Z a
Abs :: NatSingleton l => a -> Term l a -> Term (Inc l) a
App :: (NatSingleton l1, NatSingleton l2)
=> Term l1 a -> Term l2 a -> Term (Max l1 l2) a
I :: Term Z a
K :: Term Z a
S :: Term Z a
fv :: Eq a => Term l a -> [a]
fv (Var v) = [v]
fv (Abs x e) = filter (/= x) $ fv e
fv (App e1 e2) = fv e1 ++ fv e2
fv _ = []
eliminateLambda :: (Eq a, NatSingleton l) => Term (Inc l) a -> Term l a
eliminateLambda t =
case t of
Abs x t ->
case t of
Var y
| y == x -> I
| otherwise -> App K (Var y)
Abs {} -> Abs x $ eliminateLambda t
App a b -> S `App` (eliminateLambda $ Abs x a)
`App` (eliminateLambda $ Abs x b)
App a b -> eliminateLambdaApp a b
eliminateLambdaApp
:: forall a l1 l2 l .
(Eq a, Max l1 l2 ~ Inc l,
NatSingleton l1,
NatSingleton l2)
=> Term l1 a -> Term l2 a -> Term l a
eliminateLambdaApp a b =
case (sing :: SNat l1, sing :: SNat l2) of
(SInc _, SZ ) -> App (eliminateLambda a) b
(SZ , SInc _) -> App a (eliminateLambda b)
(SInc _, SInc _) -> App (eliminateLambda a) (eliminateLambda b)
convert :: forall a l . Eq a => NatSingleton l => Term l a -> Term Z a
convert t =
case sing :: SNat l of
SZ -> t
SInc _ -> convert $ eliminateLambda t
The key insight is that S, K and I are just constant Lam terms, in the same way that 1, 2 and 3 are constant Ints. It would be pretty easy to make rule 5 type-check by making an inverse to the 'convert' function:
nvert :: SKI a -> Lam a
nvert S = Abs "x" (Abs "y" (Abs "z" (App (App (Var "x") (Var "z")) (App (Var "y") (Var "z")))))
nvert K = Abs "x" (Abs "y" (Var "x"))
nvert I = Abs "x" (Var "x")
nvert (V x) = Var x
nvert (x :# y) = App (nvert x) (nvert y)
Now we can use 'nvert' to make rule 5 type-check:
convert (Abs x (Abs y e)) | x `elem` fv e = convert (Abs x (nvert (convert (Abs y e))))
We can see that the left and the right are identical (we'll ignore the guard), except that 'Abs y e' on the left is replaced by 'nvert (convert (Abs y e))' on the right. Since 'convert' and 'nvert' are each others' inverse, we can always replace any Lam 'x' with 'nvert (convert x)' and likewise we can always replace any SKI 'x' with 'convert (nvert x)', so this is a valid equation.
Unfortunately, while it's a valid equation it's not a useful function definition because it won't cause the computation to progress: we'll just convert 'Abs y e' back and forth forever!
To break this loop we can replace the call to 'nvert' with a 'reminder' that we should do it later. We do this by adding a new constructor to Lam:
data Lam a = Var a -- v
| Abs a (Lam a) -- \v . e1
| App (Lam a) (Lam a) -- e1 e2
| Com (SKI a) -- Reminder to COMe back later and nvert
deriving (Eq, Show)
Now rule 5 uses this reminder instead of 'nvert':
convert (Abs x (Abs y e)) | x `elem` fv e = convert (Abs x (Com (convert (Abs y e))))
Now we need to make good our promise to come back, by making a separate rule to replace reminders with actual calls to 'nvert', like this:
convert (Com c) = convert (nvert c)
Now we can finally break the loop: we know that 'convert (nvert c)' is always identical to 'c', so we can replace the above line with this:
convert (Com c) = c
Notice that our final definition of 'convert' doesn't actually use 'nvert' at all! It's still a handy function though, since other functions involving Lam can use it to handle the new 'Com' case.
You've probably noticed that I've actually named this constructor 'Com' because it's just a wrapped-up COMbinator, but I thought it would be more informative to take a slightly longer route than just saying "wrap up your SKIs in Lams" :)
If you're wondering why I called that function "nvert", see http://unapologetic.wordpress.com/2007/05/31/duality-terminology/ :)
Warbo is right, combinators are constant lambda terms, consequently the conversion function is
T[ ]:L -> C with L the set of lambda terms and C that of combinatory terms and with C ⊂ L .
So there is no typing problem for the rule T[λx.λy.E] => T[λx.T[λy.E]]
Here an implementation in Scala.