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

时间:2010-04-28 15:52:29

标签: haskell pattern-matching

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

{-# 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 - = ...

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

4 个答案:

答案 0 :(得分: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

你能明白为什么这不起作用吗?模式匹配中的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的纯度,并获得参考透明度。

(*)MVarIO monad中的其他此类对象是另一回事,但它们的存在不会使该点无效。

答案 1 :(得分:9)

正如 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)

答案 2 :(得分:6)

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

无法按照您想要的方式对功能进行模式匹配。

答案 3 :(得分:1)

用一个巨大的黑客来解决它。

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