3

以下函数非常简单:

test :: Int -> Int
test x = case x of
    0 -> 0
    1 -> 1
    _ -> 2

确实,test 0 == 0test 1 == 1, 和test 77 == 2

以下函数几乎同样简单:

import Data.Ratio

test2 :: Rational -> Int
test2 = case x of
    0 -> 0
    1 % 2 -> 1
    _ -> 2

在 GHCi 中加载此代码会出错Parse error in pattern: 1 % 2

是什么赋予了?为什么我不能对有理数进行模式匹配?我可以用警卫解决这个例子的现实问题,但我很好奇为什么模式匹配不起作用。

4

2 回答 2

7

通常,您不能对函数进行模式匹配。这将需要计算逆,通常甚至不存在。您只能匹配or之类的构造函数:这些可以通过以大写字符或冒号开头的普通函数/中缀运算符识别。Just:+

可以在有理数上进行模式匹配。

import GHC.Real (:%)

test2 :: Rational -> Int
test2 = case x of
    0 -> 0
    1 :% 2 -> 1
    _ -> 2

我想,为什么不真正推荐使用:%它(因此它只从内部模块导出,而不是从 导出Data.Ratio)的原因是Ratio值总是应该是最小的,但:%作为一个普通的构造函数并不能确保这一点:

Prelude Data.Ratio GHC.Real> 4%2
2 % 1
Prelude Data.Ratio GHC.Real> 4:%2
4 % 2

特别是,如果您实际上在这样一个非规范化的分数上进行模式匹配,您就不能确保成功。

在这种情况下1%2,您可以通过对小数部分进行模式匹配来规避该问题(有限小数部分是唯一的):

test2 :: Rational -> Int
test2 = case x of
    0   -> 0
    0.5 -> 1
    _   -> 2

当然,这可能不是那么好。在现代 Haskell 中,理论上可以重新定义:%为智能模式的同义词:

{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
import Data.Ratio

numDenum :: Integral a => Ratio a -> (a,a)
numDenum x = (numerator x, denominator x)

pattern (:%) :: () => Integral a => a -> a -> Ratio a
pattern a:%b <- (numDenum -> (a,b))
 where a:%b = a%b

然后可以像在您的原始示例中一样使用它。

...但坦率地说,最好直接使用numeratordenominator原样使用。

于 2016-08-18T07:43:36.240 回答
0

您也可以使用警卫来做非常相似的事情。您可以使用任意 Bool 表达式,因此您可以使用(%)和所有其他纯函数。

test3 :: Rational -> Int
test3 x | x == 0 = 0
        | x == 1 % 2 = 1
        | otherwise = 2

他们也在案例陈述中工作。

test3a :: Rational -> Int
test3a y = case y of
    x | x == 0 -> 0
      | x == 1 % 2 -> 1
      | otherwise -> 2
于 2016-08-19T04:27:23.207 回答