问题
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.
回答1:
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.
回答2:
If you want to build a truth table for boolean functions with an arbitrary number of arguments, you're creating a function that must work for multiple types, so you'll have to use type classes:
{-# LANGUAGE FlexibleInstances #-}
class TruthTable a where
truthTable :: a -> [([Bool], Bool)]
instance TruthTable Bool where
truthTable b = [([], b)]
instance TruthTable a => TruthTable (Bool -> a) where
truthTable f = [ (True : inps, out) | (inps, out) <- truthTable (f True)] ++
[ (False : inps, out) | (inps, out) <- truthTable (f False)]
For example:
*Main> mapM_ print $ truthTable (&&)
([True,True],True)
([True,False],False)
([False,True],False)
([False,False],False)
回答3:
What you're asking for is not at all trivial. Haskell doesn't make it easy to deal with functions that apply functions with variable numbers of arguments. For example, the zip functions from Data.List come in separate variants for different numbers of arguments (zip
, zip3
, zip4
, ...). Likewise, in Control.Monad there's liftM
, liftM2
, liftM3
, ...
Basically, the most general type you can assign to a function with an unknown number of arguments is a -> b
; a one-place truth function is Bool -> Bool
(a = Bool
, b = Bool
), a two-place truth function is Bool -> (Bool -> Bool)
(a = Bool
, b = Bool -> Bool
), three-place is Bool -> (Bool -> (Bool -> Bool))
(a = Bool
, b = Bool -> (Bool -> Bool)
), and so on. But there is no easy way you can look at the function you've been passed in to know what's the type on the right of the initial arrow.
One type of solution that can be made to work involves using type classes to define separate instances of the truth-table maker function for each argument function type. Sjoerd Visscher's answer in this thread is doing that for all function sizes by using a recursive instance definition (notice the recursive TruthTable a => TruthTable (Bool -> a)
declaration). There may be other solutions that could be constructed using the Applicative
type class.
来源:https://stackoverflow.com/questions/8478067/truth-tables-from-anonymous-functions-in-haskell