0

以下代码旨在将布尔值的 Church 编码打印为 Haskell's 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)

如何让它发挥作用?

4

1 回答 1

5

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


一种可能的解决方案是通过BoolFlexibleInstances是必要的)专门化您的实例

{-#LANGUAGE FlexibleInstances #-}

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

但这会降低您的 Church 布尔值的一般性。

定义适用于任何类型的灵活解决方案是不可能的,因为您将需要该类型的两个代表来描述真假情况,并且有些类型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
  • 至少有两个有效且不同的类型值t显示为truefalse

以这种方式实际能够实现show此类签名的功能需要哪些情况。

重要的

以下示例不起作用:

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

问题是 typechecker 不会猜测t你将在这里使用哪个。此解决方案提供有效且有效的实例,但仅适用于完全实例化的类型。如果出现歧义错误,则需要指定什么是t

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

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

编辑

评论中还提到了另一个想法。解决方案是将您的 Church 布尔值包装为Rank2Type

{-# LANGUAGE Rank2Types #-}

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

这将让t任何类型独立于上下文。然后你可以定义这样的临时实例:

instance Show ChBool where
  show (ChBool f) = show $ f True False
于 2019-03-09T14:24:18.633 回答