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

前端 未结 1 1670
感动是毒
感动是毒 2021-01-30 20:40

I\'m trying to create a function that gets a variadic function as an argument, i.e.

func :: (a -> ... -> a) -> a

how can I ac

1条回答
  •  被撕碎了的回忆
    2021-01-30 21:19

    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
    

    0 讨论(0)
提交回复
热议问题