Haskell中Rationals上的模式匹配

dvi*_*tek 3 rational-number haskell pattern-matching rational-numbers

以下函数非常简单:

test :: Int -> Int
test x = case x of
    0 -> 0
    1 -> 1
    _ -> 2
Run Code Online (Sandbox Code Playgroud)

事实上,test 0 == 0test 1 == 1,和test 77 == 2.

以下功能几乎一样简单:

import Data.Ratio

test2 :: Rational -> Int
test2 = case x of
    0 -> 0
    1 % 2 -> 1
    _ -> 2
Run Code Online (Sandbox Code Playgroud)

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

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

lef*_*out 7

通常,您不能在函数上进行模式匹配.这将需要计算逆,这通常甚至不存在.你只能匹配构造类似Just:+:这些都是普通函数/缀运营商识别用大写字符或冒号开始.

可以在理性上进行模式匹配.

import GHC.Real (:%)

test2 :: Rational -> Int
test2 = case x of
    0 -> 0
    1 :% 2 -> 1
    _ -> 2
Run Code Online (Sandbox Code Playgroud)

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

Prelude Data.Ratio GHC.Real> 4%2
2 % 1
Prelude Data.Ratio GHC.Real> 4:%2
4 % 2
Run Code Online (Sandbox Code Playgroud)

特别是,如果您实际上在这样的非标准化分数上进行模式匹配,则无法确定是否成功.

在类似情况下1%2,您可以通过小数部分上的模式匹配来规避问题(有限小数部分是唯一的):

test2 :: Rational -> Int
test2 = case x of
    0   -> 0
    0.5 -> 1
    _   -> 2
Run Code Online (Sandbox Code Playgroud)

当然,这可能不是那么好.在现代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
Run Code Online (Sandbox Code Playgroud)

然后可以在原始示例中使用它.

......但坦率地说,它可能会更好只使用numeratordenominator,因为它们.