Search code examples
haskellbooleanlogictruthtable

Truth Tables from Anonymous Functions in Haskell


I'm trying to generate a truth table for a given boolean expression. I could do this with creating a new Datatype BoolExpr, but I want to do it with an anonymous function. It's supposed to work like this:

> tTable (\x y -> not (x || y))
output:
F F | T
F T | F
T F | F
T T | F

My approach:

tbl p = [(uncurry p) tuple | tuple <- allval]
        where allval=[(x,y) | x <- [False,True], y <- [False,True]]

This works, but only for 2 Arguments. I want to do it for any number of Arguments. So I figured I would make a function that takes the Arguments from a List:

argsFromList f []     = f
argsFromList f (x:xs) = argsFromList (f x) xs

This does not work:

 Occurs check: cannot construct the infinite type: t = t1 -> t
   Expected type: t -> [t1] -> t1 -> t
   Inferred type: (t1 -> t) -> [t1] -> t1 -> t
 In the expression: argsFromList (f x) xs

I don't understand what the problem is here. I would be very grateful if anyone could point me into the right direction or post a link that does.


Solution

  • The problem here is that you're trying to call a function recursively with a different type for the recursive step. Consider the definition:

    argsFromList f []     = f
    argsFromList f (x:xs) = argsFromList (f x) xs
    

    Let's try to infer the type ourselves. We can immediately see that the first argument f should be a function of at least one argument, the second argument (x:xs) is a list, and the list elements should be the same type as the first argument of f. In the first case the argument f is returned, so the final return type must be the same as the first argument. So we start with this:

    argsFromList :: (a -> ?) -> [a] -> (a -> ?)
    

    To find the unknown type ?, we can look at the second case, which consists of a recursive call. The argument xs is the same list type, and the argument (f x) has type ?. Since it's being used as the first argument in the recursive call, which has type (a -> ?), we can now conclude that ? is the same type as (a -> ?) which is therefore the same type as (a -> (a -> ?)) which is therefore the same type as (a -> (a -> (a -> ?))) which is... oops.

    That would be the "infinite type", of course.

    If you want to do this with functions that use a variable number of arguments of a single type, you'll probably want to use functions that take a list of values rather than individual arguments. Otherwise, you'll have to either write each version individually or use some arcane tricks involving advanced language features, neither of which is appealing in a simple case like this.