1

モジュラスを取得して0かどうかをチェックすることで、ある整数が別の整数を割るかどうかをチェックする簡単な関数を作成しようとしています.私の考えは次のようなものでした

divides :: (Integral a) => a -> a -> Bool
divides = (==0) . (flip mod)

ここで、a が b を割る場合、ab を割ると真になります。ただし、このコードではエラーが発生します

Couldn't match expected type `a -> Bool' with actual type `Bool'
Expected type: b0 -> a -> Bool
 Actual type: b0 -> Bool
In the first argument of `(.)', namely `(== 0)'
In the expression: (== 0) . mod

このコードが機能しない理由が本当にわかりません。教えてください!

4

3 に答える 3

6

要点は、.各関数に1つの引数のみをフィードしますが、flip mod2つ必要です。簡単な解決策は

(.:) = (.) . (.) -- the owl or boobs operator

divides = (0==) .: flip mod

どこ.:ですか

 (c -> d) -> (a -> b -> c) -> a -> b -> d
于 2013-11-09T17:47:04.527 に答える
4

コードの何が問題なのかを確認するには、手動で eta 展開します。

divides :: (Integral a) => a -> a -> Bool
divides = (==0) . (flip mod)
-- divides x = ((==0) . (flip mod)) x
--           = ((==0) $ flip mod x)
--           = flip mod x == 0

その最後の行は型チェックをしてい(==) :: a -> a -> Boolません。divides xa -> BoolBool

コードを修正する最も簡単な方法は、より拡張された形式で記述することです。たとえば、次のようになります。

divides :: (Integral a) => a -> a -> Bool
divides x = (==0) . (`mod` x)

本当に eta-reduced で書きたい場合は、次のようになります。

divides :: (Integral a) => a -> a -> Bool
divides = ((==0).) . (flip mod)
-- divides x = ((==0).) $ (`mod` x)
--           = (==0) . (`mod x`)  
于 2013-11-09T17:37:42.803 に答える
2

.演算子がflip mod結果に 2 つの引数を取るという事実を引き継ぐことを期待しているようです。あなたはこれを期待しています:

f :: a -> b -> c
g :: c -> d
g . f :: a -> b -> d

残念ながら、そのようには機能しません。関数は常に単一の引数を取り、複数の引数関数は、関数を返す関数を持つことによって「シミュレート」されます。たとえば、a -> b -> cと読むことができますa -> (b -> c)。したがって、次のようになります。

f :: a -> (b -> c)
g :: (b -> c) -> d
g . f :: a -> d

したがって、なぜg(== 0)あなたの場合は)関数が必要であり、関数のタイプは実際にはa -> Boolありませんa -> a -> Bool

于 2013-11-09T17:42:52.123 に答える