Mykhailo Iaremenko
Mykhailo Iaremenko

Reputation: 63

Haskell function construction

I am learning Haskell and stacked in one weird problem. I have a long expression and I need to devide it into small expressions and log them. I've managed to solve that part but I cannot understand why I cannot add details for (Const Bool) to all details.

module MonadicInterpreterLog where

import Test.HUnit (runTestTT,Test(TestLabel,TestList),(~?=))

import Control.Monad 
import Control.Applicative hiding (Const)

-- Simple Boolean expressions
data Expr = Const Bool | And Expr Expr | Or Expr Expr
  deriving (Eq, Show, Read)

sample1 = And (Const True) (Or (Const False) (Const True))
sample2 = And (Or (Const False) (Const True)) (And (Const False) (Const True))

eval' :: Expr -> [Expr] -> (Bool, [Expr])
eval' (Const b) es = (b, Const b : es)
eval' (And e1 e2) es = (checkValue e1 && checkValue e2, And e1 e2 : e1 : e2 : es)
eval' (Or e1 e2) es = (checkValue e1 || checkValue e2, Or e1 e2 : e1 : e2 : es)

checkValue :: Expr -> Bool
checkValue (Const b) = b
checkValue (And e1 e2) = checkValue e1 && checkValue e2
checkValue (Or e1 e2) = checkValue e1 || checkValue e2



main :: IO ()
main = do
    testresults <- runTestTT tests
    print testresults

testlog1, testlog2 :: [Expr]
testlog1 = [(And (Const True) (Or (Const False) (Const True))),
        (Const True),
        (Or (Const False) (Const True)),
        (Const False),
        (Const True)]
testlog2 = [(And (Or (Const False) (Const True)) (And (Const False) (Const True))),
             (Or (Const False) (Const True)),
             (Const False),
             (Const True),
             (And (Const False) (Const True)),
             (Const False),
             (Const True)]

-- | List of tests for 'parseScore'.
tests :: Test
tests = TestLabel "MonadicInterpreterLog" (TestList [
    eval' sample1 [] ~?= (True,testlog1),
    eval' sample2 [] ~?= (False,testlog2)
    ])

The error message I get:

MonadicInterpreterLog.hs:96 
expected: (True,[And (Const True) (Or (Const False) (Const True)),Const True,Or (Const False) (Const True),Const False,Const True])
but got: (True,[And (Const True) (Or (Const False) (Const True)),Const True,Or (Const False) (Const True)]) 

So as you see the part for (Const Bool) is missing. What wrong am I doing? Thank you in advance

Upvotes: 2

Views: 153

Answers (1)

Zeta
Zeta

Reputation: 105955

While checkValue is recursive, eval' isn't. We can show this with a smaller example:

true   = Const True
small1 = And true $ And true $ And true true
ghci> eval' small1
(True,[
 And (Const True) (And (Const True) (And (Const True) (Const True))), -- level 1
 Const True, And (Const True) (And (Const True) (Const True))         -- level 2
  -- other levels missing
 ])

You have to apply eval' recursively on es1 and es2. Even better, have eval actually evaluate the expressions fully:

eval :: Expr -> (Bool, [Expr])
eval expr = case expr of
    Const b   -> (b, [expr])
    And e1 e2 -> evalWith (&&) e1 e2
    Or  e1 e2 -> evalWith (||) e1 e2 
  where
    evalWith op e1 e2 = 
      let (b1, es1') = eval e1
          (b2, es2') = eval e2
      in (b1 `op` b2, expr : (es1' ++ es2'))

Upvotes: 5

Related Questions