0

I am constructing a basic function in Haskell that return the list of variables that appear in a Boolean expression.

For some reason I am stuck in a test case.

I am a still beginner so can someone explain what's happening here?

Here is the code:

module BoolExpr (Variable, BoolExpr(..), evaluate) where
import Data.List
import System.IO

type Variable = Char
data BoolExpr = T
 |F
 |Var Variable
 |Not BoolExpr
 |And BoolExpr BoolExpr
 |Or BoolExpr BoolExpr
 deriving(Show)


-- evaluates an expression
evaluate :: BoolExpr -> [Variable] -> Bool
evaluate T _            = True
evaluate F _            = False
evaluate (Var v) vs     = v `elem` vs
evaluate (Not e) vs     = not (evaluate e vs)
evaluate (And e1 e2) vs = evaluate e1 vs && evaluate e2 vs
evaluate (Or  e1 e2) vs = evaluate e1 vs || evaluate e2 vs




--here is the function
variables :: BoolExpr -> [Variable]
variables (Or T F) = []
variables (And T F) = []
variables (Var  a)= [a]
variables (Or (Var a) (Var b)) =[a]++[b]
variables (And (Var a) (Var b))=[a]++[b]
variables T = []
variables F = []


subsets :: [Variable] -> [[Variable]]
subsets [] = [[]]
subsets (x:xs) = [zs | ys <- subsets xs, zs <- [ys, (x:ys)]]

input : variables (And (Var 'a') (Or (Var 'c') (Var 'b')))

output: Non-exhaustive patterns in function variables

expected output: "abc"

other test cases:

input:variables (And (Var 'a') (Or (Var 'a') (Var 'a')))

expected output: "a" `

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
John C.
  • 405
  • 5
  • 19
  • Note that, unless I've misunderstood what the function is supposed to do, the best way to define this function is to have one case for each constructor and use recursion for those constructors which hold `BoolExpr` values themselves. Which is exactly what you've already (and correctly) done in `evaluate`. – Robin Zigmond Oct 31 '19 at 07:48
  • 2
    You are only handling very specific cases like `variables (Or T F) = []`. You should remove that and similar lines, and instead provide a definition of the form `variables (Or e1 e2) = ...` handling the case where `e1` and `e2` are _arbitrary_ formulas. You already did that for `evaluate` in your own code. You'll need to use recursion, as you did for `evaluate`. – chi Oct 31 '19 at 08:16

1 Answers1

3

If you turn on the compiler warning for incomplete patterns, the compiler will tell you which patterns have no matches:

Prelude> :set -Wincomplete-patterns
Prelude> :l 58637724.hs
[1 of 1] Compiling BoolExpr         ( 58637724.hs, interpreted )

58637724.hs:29:1: warning: [-Wincomplete-patterns]
    Pattern match(es) are non-exhaustive
    In an equation for `variables':
        Patterns not matched:
            (Not _)
            (And T T)
            (And T (Var _))
            (And T (Not _))
            ...
   |
29 | variables (Or T F) = []
   | ^^^^^^^^^^^^^^^^^^^^^^^^...
Ok, one module loaded.

Add those cases to the variables function, and the problem should go away.

Notice the ellipsis (...) after the first four patterns. That indicates that there's more unmatched patterns, so once you've addressed those four missing patterns, look at the compiler warning again.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • 1
    Hint: you can use `variables _ = []` to catch "everything that doesn't match one of the above patterns" and shorten the definition. – luqui Oct 31 '19 at 07:02