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中的其他此类对象是另一回事,但它们的存在并不会使这一点无效。正如sepp2k和MtnViewMark所说,您不能对标识符的值进行模式匹配,只能对构造函数进行模式匹配,在某些情况下,还可以进行隐式相等性检查。因此,在隐藏(+)
的外部定义的过程中,您的实例正在将任何参数绑定到标识符。不幸的是,这意味着你试图做的不会也永远不会起作用
您想要完成的一个典型解决方案是定义一个“算术表达式”代数数据类型,并使用适当的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
的一个非常合理的实例。