How to write a Haskell function that takes a variadic function as an argument

怎甘沉沦 提交于 2019-12-02 15:47:09

The trick is to make a type class for which you will define an instance for functions, and an instance for the return type. The fact that it's a Bool is not a problem at all.

We're trying to write a function which takes a variadic argument and returns a Bool, so we'll define a type class with such a function.

class Stmt a where
    tautology :: a -> Bool

Next, we define an instance for the return type of the variadic function. In this case, that's Bool.

-- A Bool is a tautology if it's True.
instance Stmt Bool where
    tautology = id

The key part is the next instance for functions that take a Bool argument, and whose return type is some type from our class. That way, this instance will be applied multiple times if a function takes multiple arguments.

-- A function is a tautology if it always returns a tautology.
instance Stmt b => Stmt (Bool -> b) where
    tautology f = tautology (f True) && tautology (f False)

Writing it this way requires FlexibleInstances because of the Bool in the second instance head. To do the same with pure Haskell 98, we'll need to use a suitably-constrained type variable instead. We can for example use Bounded and Enum (there are instances for both for Bool), or you can make your own class that will let you construct the appropriate inputs.

instance (Enum a, Bounded a, Stmt b) => Stmt (a -> b) where
    tautology f = all (tautology . f) [minBound .. maxBound]

And we're done. Let's try it out:

> tautology $ \x y -> (not x && not y) == not (x && y)
False
> tautology $ \x y -> (not x && not y) == not (x || y)
True
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!