打印教堂布尔值

时间:2019-03-09 13:16:46

标签: haskell types type-inference church-encoding

以下代码旨在将布尔型的Church编码打印为Haskell的Bool

{-#LANGUAGE FlexibleInstances #-}

instance Show (t -> t -> t) where
  show b = show $ b True False

哪个会导致此错误:

<interactive>:4:21: error:
• Couldn't match expected type ‘t’ with actual type ‘Bool’
  ‘t’ is a rigid type variable bound by
    the instance declaration at <interactive>:3:10-27
• In the first argument of ‘b’, namely ‘True’
  In the second argument of ‘($)’, namely ‘b True False’
  In the expression: show $ b True False
• Relevant bindings include
    b :: t -> t -> t (bound at <interactive>:4:8)
    show :: (t -> t -> t) -> String (bound at <interactive>:4:3)

如何使其工作?

1 个答案:

答案 0 :(得分:5)

问题是show :: (t -> t -> t) -> String应该适用于 any 类型t上的 any 函数。您假设t是布尔值,这是非法的,因为(根据GHC)“ t是刚性类型变量”并且不能与专用类型统一。


一种可能的解决方案是通过Bool(必须使用FlexibleInstances)来专门化您的实例

{-#LANGUAGE FlexibleInstances #-}

instance Show (Bool -> Bool -> Bool) where
  show b = show $ b True False

但是,这将降低您的教堂布尔值的通用性。

不可能定义适用于任何类型的灵活解决方案,因为您将需要具有该类型的两个代表来描述 true false 情况,并且类似Void之类的类型都没有(定义)值。


我想到一个很普遍的想法,就是为t添加更多的类约束:

{-#LANGUAGE FlexibleInstances #-}
import Data.Boolean

instance (Show t, Boolean t) => Show (t -> t -> t) where
  show b = show $ b true false

Boolean类收集在某些术语中可以理解为逻辑值的类型。例如Bool

instance Boolean Bool where
  true = True
  false = False
  notB = not
  (||*) = (||)
  (&&*) = (&&)

现在我们可以确保

  • t是您实际上可以show
  • 至少有两个类型分别为ttrue的有效false类型的有效值

实际上需要以哪种方式show进行这种签名的功能?

重要

以下示例不起作用:

show (true :: (Show t, Boolean t) => t -> t -> t) 

问题在于,类型检查器不会猜测您将在此处使用哪个t。该解决方案提供了有效且有效的实例,但仅适用于完全实例化的类型。如果出现歧义错误,则需要指定t

show (true :: Bool -> Bool -> Bool)
>>> "True"

show (true :: Int -> Int -> Int)  -- assuming Boolean instance
>>> "1"

编辑

但评论中提到了另一个想法。解决方案是用Rank2Type将您的布尔布尔值包装起来:

{-# LANGUAGE Rank2Types #-}

newtype ChBool = ChBool (forall t. t -> t -> t)

t设置为与上下文无关的任何类型。然后,您可以这样定义临时实例:

instance Show ChBool where
  show (ChBool f) = show $ f True False