Haskell 使用函数实例显示的奇怪模式匹配

Haskell 使用函数实例显示的奇怪模式匹配,haskell,pattern-matching,Haskell,Pattern Matching,所以我正在写一个程序,它返回一个给定算术问题的过程,所以我想引用几个函数来演示,这样我就可以打印出测试时计算的相同表达式。问题是,给定的代码在应该落在第二行时,却与第一行匹配(-) {-# OPTIONS_GHC -XFlexibleInstances #-} instance Show (t -> t-> t) where show (+) = "plus" show (-) = "minus" main = print [(+),(-)] 返回 [plus,pl

所以我正在写一个程序,它返回一个给定算术问题的过程,所以我想引用几个函数来演示,这样我就可以打印出测试时计算的相同表达式。问题是,给定的代码在应该落在第二行时,却与第一行匹配(-)

{-# OPTIONS_GHC -XFlexibleInstances #-}

instance Show (t -> t-> t) where  
 show (+) = "plus"
 show (-) = "minus"  

main = print [(+),(-)]
返回

[plus,plus]
我只是在一开始就犯下了致命的罪,还是有什么方法可以让它正确匹配

编辑:我意识到我收到了以下警告:

Warning: Pattern match(es) are overlapped
         In the definition of `show': show - = ...

我仍然不知道它为什么重叠,或者如何停止它。

它重叠,因为它将
(+)
简单地视为一个变量,这意味着在RHS上,标识符+将绑定到您调用的函数show on


没有办法按照您想要的方式对函数进行模式匹配。

这里有一种方法来考虑这个问题。考虑:

answer = 42
magic = 3

specialName :: Int -> String
specialName answer = "the answer to the ultimate question"
specialName magic = "the magic number"
specialName x = "just plain ol' " ++ show x
你能明白为什么这行不通吗<模式匹配中的code>answer是一个变量,不同于外部范围中的
answer
。因此,你必须这样写:

answer = 42
magic = 3

specialName :: Int -> String
specialName x | x == answer = "the answer to the ultimate question"
specialName x | x == magic = "the magic number"
specialName x = "just plain ol' " ++ show x
事实上,这正是在模式中写入常量时发生的情况。即:

digitName :: Bool -> String
digitName 0 = "zero"
digitName 1 = "one"
digitName _ = "math is hard"
由编译器转换为与以下内容等效的内容:

digitName :: Bool -> String
digitName x | x == 0 = "zero"
digitName x | x == 1 = "one"
digitName _ = "math is hard"
由于您希望与绑定到
(+)
的函数匹配,而不仅仅是将任何内容绑定到符号
(+)
,因此您需要将代码编写为:

instance Show (t -> t-> t) where  
 show f | f == (+) = "plus"
 show f | f == (-) = "minus"
但是,这要求函数在相等性方面具有可比性。这通常是一个不可判定的问题

您可能会反驳说,您只是要求运行时系统比较函数指针,但在语言级别,Haskell程序员没有访问指针的权限。换句话说,您不能操作对Haskell(*)中值的引用,只能操作值本身。这是Haskell的纯度,并获得了参考透明度


(*)
MVar
s和
IO
monad中的其他此类对象是另一回事,但它们的存在并不会使这一点无效。

正如sepp2kMtnViewMark所说,您不能对标识符的值进行模式匹配,只能对构造函数进行模式匹配,在某些情况下,还可以进行隐式相等性检查。因此,在隐藏
(+)
的外部定义的过程中,您的实例正在将任何参数绑定到标识符。不幸的是,这意味着你试图做的不会也永远不会起作用

您想要完成的一个典型解决方案是定义一个“算术表达式”代数数据类型,并使用适当的
show
实例。请注意,您可以将表达式类型本身设置为
Num
的实例,将数值文本包装在“Literal”构造函数中,像
(+)
这样的操作将其参数与操作的构造函数组合返回。下面是一个快速但不完整的示例:

data Expression a = Literal a
                  | Sum (Expression a) (Expression a)
                  | Product (Expression a) (Expression a)
                  deriving (Eq, Ord, Show)

instance (Num a) => Num (Expression a) where
    x + y = Sum x y
    x * y = Product x y
    fromInteger x = Literal (fromInteger x)

evaluate (Literal x) = x
evaluate (Sum x y) = evaluate x + evaluate y
evaluate (Product x y) = evaluate x * evaluate y

integer :: Integer
integer = (1 + 2) * 3 + 4

expr :: Expression Integer
expr = (1 + 2) * 3 + 4
在GHCi中尝试:

> integer
13
> evaluate expr
13
> expr
Sum (Product (Sum (Literal 1) (Literal 2)) (Literal 3)) (Literal 4)

我自己用一个超级黑客解决了这个问题

instance (Num t) => Show (t -> t-> t) where  
show op =
    case (op 6 2) of
        8 -> "plus"
        4 -> "minus"
        12 -> "times"
        3 -> "divided"

一切都清楚了!我也试着做了(+)和(-)的情商实例,但显然(现在)也没有意义。谢谢你的回答。太棒了,谢谢。(比我下面给出的解决方案要优雅得多。)@Sean D:这也很好地说明了你的超级黑客会失败的地方——想想如果它与
表达式整型
值上的运算符一起使用会发生什么
Sum 6 2
不等于
Literal 8
,尽管我的代码是
Num
的一个非常合理的实例。