与函数实例展示的奇怪模式匹配

6 haskell pattern-matching

所以我正在编写一个程序,它返回一个给定算术问题的过程,所以我想实现一些Show的函数,以便我可以打印我测试时评估的相同表达式.问题是给定的代码匹配( - )到第一行时应该落到第二行.

{-# OPTIONS_GHC -XFlexibleInstances #-}

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

main = print [(+),(-)]
Run Code Online (Sandbox Code Playgroud)

回报

[plus,plus]
Run Code Online (Sandbox Code Playgroud)

我只是首先承诺一个致命的印刷功能,还是有一些方法可以让它正确匹配?

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

Warning: Pattern match(es) are overlapped
         In the definition of `show': show - = ...
Run Code Online (Sandbox Code Playgroud)

我仍然不知道为什么它会重叠,或者如何阻止它.

Mtn*_*ark 9

这是一种思考这个问题的方法.考虑:

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
Run Code Online (Sandbox Code Playgroud)

你能明白为什么这不起作用吗?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
Run Code Online (Sandbox Code Playgroud)

实际上,这就是在模式中编写常量时正在发生的事情.那是:

digitName :: Bool -> String
digitName 0 = "zero"
digitName 1 = "one"
digitName _ = "math is hard"
Run Code Online (Sandbox Code Playgroud)

由编译器转换为等效于:

digitName :: Bool -> String
digitName x | x == 0 = "zero"
digitName x | x == 1 = "one"
digitName _ = "math is hard"
Run Code Online (Sandbox Code Playgroud)

由于您希望匹配绑定的函数(+)而不是仅将任何内容绑定到符号(+),因此您需要将代码编写为:

instance Show (t -> t-> t) where  
 show f | f == (+) = "plus"
 show f | f == (-) = "minus"
Run Code Online (Sandbox Code Playgroud)

但是,这将要求功能在平等性方面具有可比性. 这一般是一个不可判定的问题.

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

(*)MVars和IOmonad中的其他此类对象是另一回事,但它们的存在并不会使这一点无效.


C. *_*ann 9

正如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
Run Code Online (Sandbox Code Playgroud)

在GHCi中尝试:

> integer
13
> evaluate expr
13
> expr
Sum (Product (Sum (Literal 1) (Literal 2)) (Literal 3)) (Literal 4)
Run Code Online (Sandbox Code Playgroud)


sep*_*p2k 6

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

无法按照您想要的方式对函数进行模式匹配.