我目前正在尝试为xor实现lambda表达式。但是,我觉得我错过了一些东西,因为我从bxor表达式中得到了错误。我做错了什么?
true = \t f -> t -- always pick the first argument
false = \t f -> f -- always pick the second argument
toBool = \b -> b True False
bnot = \b -> b true false
bxor = \b x -> b (bnot x) x
答案 0 :(得分:5)
在打字环境中,需要小心。你的lambda术语在无类型设置中工作正常,但需要在键入的设置中进行一些调整。
我们需要为Church booleans定义一个类型。让我们选择以下参数单态类型。
type B a = a -> a -> a
然后,让我们添加类型注释以检查错误:
true :: B a
true = \t f -> t
false :: B a
false = \t f -> f
toBool :: B Bool -> Bool
toBool = \b -> b True False
到目前为止,这么好。但是:
bnot :: B a -> B a
bnot = \b -> b false true
会产生类型错误,例如false
的类型为B a
,而不是a
,因此应用b false
的类型不合适。我们可以通过添加几个a
参数x y
来解决这个问题,并相应地简化函数。
bnot = \b x y -> b (false x y) (true x y)
-- or, more simply:
bnot = \b x y -> b y x
-- or even
bnot = flip
此类型检查。同样,我们可以返工bxor
进行类型检查:
bxor :: B a -> B a -> B a
bxor = \b1 b2 x y -> b1 (bnot b2 x y) (b2 x y)
或者,使用布隆的 impredicative Church编码,除了添加相关类型签名外,我们可以使原始代码按原样进行检查。这需要更高级别的类型。
{-# LANGUAGE Rank2Types #-}
type BI = forall a. a -> a -> a
trueI :: BI
trueI = true
falseI :: BI
falseI = false
toBoolI :: BI -> Bool
toBoolI = \b -> b True False
bnotI :: BI -> BI
bnotI = \b -> b falseI trueI
bxorI :: BI -> BI -> BI
bxorI = \b x -> b (bnotI x) x