Warm tip: This article is reproduced from stackoverflow.com, please click
abstract-syntax-tree haskell

traversal of boolean AST in Haskell

发布于 2020-04-10 10:20:05

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.

Questioner
clickedok
Viewed
65
chi 2020-02-02 16:36

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 (&&) (||)