Haskell中rationls的模式匹配



下面的函数非常简单:

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

test 0 == 0, test 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

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

一般不可以对函数进行模式匹配。这需要计算逆函数,而逆函数通常不存在。您只能在构造函数上匹配,如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可能会更好。

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

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

它们也适用于case语句。

test3a :: Rational -> Int
test3a y = case y of
    x | x == 0 -> 0
      | x == 1 % 2 -> 1
      | otherwise -> 2

相关内容

  • 没有找到相关文章

最新更新