2016-08-18 5 views
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を与えます。

何がありますか?なぜ私は有理数に対してパターンマッチングできないのですか?私はこの例題がガードから来た実際の問題を解決することができますが、なぜパターンマッチングがうまくいかないのか不思議です。

答えて

7

一般に、関数のパターンマッチングはできません。それは通常は存在しない逆行列の計算を必要とするでしょう。 のコンストラクタ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では、1は、理論的にはスマートなパターンの同義語として:%を再定義することができます。そして、あなたの元の例のように使用することができ

{-# 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をそのまま使用する方が良いでしょう。

+0

これはちょうどひどく、私はおそらくそれを受け入れるでしょう。しかし、なぜパターンマッチングできないのかという疑問には答えていません(%)。私はパターンマッチングの内部を特によく知っているわけではないので、私が見ていない簡単な答えがあるかもしれません。 – dvitek

+0

そうですね、私はそれをトップに追加しました。 – leftaroundabout

+0

ああ、そうだ。私は '(%)'が実際にはコンストラクタではないことに気付かなかったのですが、 ':info'を見るだけで、明らかにそうではありません。有限小数点法のアプローチは、小数点のデフォルトの「分数a」型の賢明な使用です。これは私が忘れていたものです。 私はスマートパターンの同義語の答えをよく理解していません - 私は恐竜ハスケルを使用していますが、読めるようになっているようです。すばらしい答えの束をありがとう! – dvitek

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