Reputation: 47
I am having trouble completing a task where I am to create a function that uses a generalised fold function to evaluate a boolean AST. I will show you some examples to illustrate.
First, an example of what I want, but for an AST that sums integers:
data Expr = Val Int | Add Expr Expr deriving Show
folde :: (Int -> a) -> (a -> a -> a) -> Expr -> a
folde f g (Val x) = f x
folde f g (Add x y) = g (folde f g x) (folde f g y)
eval :: Expr -> Int
eval expr = folde (\x -> x) (\x y -> x + y) expr
This works fine.
Now for the boolean AST, and the folding function:
data Bexp = T | F | And Bexp Bexp | Or Bexp Bexp deriving (Ord, Eq)
foldb :: a -> a -> (a -> a -> a) -> (a -> a -> a) -> Bexp -> a
foldb t f a o T = t
foldb t f a o F = f
foldb t f a o (And x y) = a (foldb t f a o x) (foldb t f a o y)
foldb t f a o (Or x y) = o (foldb t f a o x) (foldb t f a o y)
What I am having trouble with, is creating a function that does the same as the eval function does for the simple AST above, that is, using the foldb function with some lambdas to evaluate whether the Bexp
expression is either T
or F
.
I don't understand why this function doesn't work:
evb :: Bexp -> Bool
evb bexp = foldb (\_ -> True) (\_ -> False) (\x y -> x == T && y == T) (\x y -> x == T || y == T) bexp
GHCi doesn't even wanna to compile it because of type error.
Thanks in advance.
Upvotes: 1
Views: 291
Reputation: 116174
If we want to use foldb
to produce a Bool
at the very end, we need to choose a = Bool
in its type. So, we are now using
foldb :: Bool
-> Bool
-> (Bool -> Bool -> Bool)
-> (Bool -> Bool -> Bool)
-> Bexp
-> Bool
Hence, foldb (\_->True) (\_->False) ...
is wrong since the first two arguments must be booleans, not functions. We need something like foldb True False ...
.
The next two parameters must be boolean binary operators like \x y -> x && y
, which can be written as (&&)
for short.
We finally get:
evb :: Bexp -> Bool
evb bexp = foldb True False (&&) (||)
Upvotes: 1
Reputation: 1543
The code does't compile for few reasons.
-- Observe type signatures.
foldb :: a -> a -> (a -> a -> a) -> (a -> a -> a) -> Bexp -> a
evb bexp = foldb (\_ -> True) (\_ -> False) (\x y -> x == T && y == T) (\x y -> x == T || y == T) bexp
If foldb
takes its first argument as a Function x -> Bool
then from the type signature of foldb
a
is of type function but observe this (\x y -> x == T && y == T)
here you used a
as Bexp
, which don't match at all.
a
= Bexp
from (\x y -> x == T && y == T)
a
= x -> Bool
from (\_ -> True)
And also the return type of evb
is Bool
, but from your argument passing to foldb
a
can be 2 things & the compiler is confused to pick the right type.
Upvotes: 3