Haskell中如何用类型签名表示任意函数?泛化多参数谓词函数
泛化
orElse以支持任意参数个数的谓词函数 首先直接回答你的核心疑问:Haskell没法在类型签名里直接写出“任意类型的函数”,但可以通过类型类(Typeclass)抽象出“最终返回Bool的任意参数函数”这一类类型,从而实现你要的泛化。
实现思路
我们可以定义一个类型类,用来描述所有“能被orElse处理”的类型——也就是所有返回Bool的函数(不管参数个数多少)。然后通过递归的类型类实例,自动适配不同参数长度的函数。
具体代码
首先定义类型类和基础实例:
class Predicate f where orElse :: Bool -> f -> f -- 基础实例:直接处理Bool值(相当于0参数的谓词) instance Predicate Bool where orElse True _ = True orElse False b = b -- 递归实例:如果r是Predicate,那么接收一个参数后返回r的函数也是Predicate instance Predicate r => Predicate (a -> r) where orElse True _ = \_ -> orElse True (undefined :: r) orElse False func = \x -> orElse False (func x)
用法示例
现在这个orElse可以处理任意参数个数的谓词函数了:
-- 1参数谓词 oneArg :: Int -> Bool oneArg = orElse True even -- 无论输入什么整数,都返回True -- 2参数谓词 twoArg :: Int -> String -> Bool twoArg = orElse False (\num str -> num > 0 && str /= "") -- 仅当第一个参数为False时,调用原谓词 -- 0参数(直接处理Bool) zeroArg :: Bool zeroArg = orElse True False -- 返回True
原理说明
- 类型类
Predicate作为约束,限定了所有可以被orElse处理的类型。 - 递归实例利用了Haskell函数类型的右结合性:
a -> b -> Bool本质是a -> (b -> Bool),所以只要b -> Bool是Predicate,a -> (b -> Bool)也自动成为Predicate,以此类推,支持任意多层参数。 - 当第一个参数为
True时,我们生成一个“恒返回True”的对应参数个数的函数;为False时,直接返回原函数。
内容的提问来源于stack exchange,提问作者Max Motovilov
相关产品推荐
相关产品推荐

