2016-01-12 9 views
5

私はHaskellを介した関数型プログラミングを理解しようとしていますが、関数の構成を扱うには非常に問題があります。2つのパラメータを持つHas​​kellの構成

実は私は、これらの二つの機能を持っている:

add:: Integer -> Integer -> Integer 
add x y = x + y 

sub:: Integer -> Integer -> Integer 
sub x y = x - y 

は、私はそれらを構成することができるようにしたいです。何の意味もありませんが、学習目標です。

foo:: (Integer -> Integer) -> (Integer -> Integer) -> Integer 
foo = add . sub 

を私が理解した内容::私たちは、それぞれの後に実行するための新しい関数を返すように

Haskellは、唯一の引数で関数を使用して、私が試した何

関数の実行。

したがって、最初のIntegerはparam型ですが、2番目は生成された関数の戻り型で、2番目の数値を追加する必要があります。

これは、別の関数(sub)を返すよう意志が(...のparamsなどで機能を返す)と同じ流れを作る

は、私は右ですか?私は私が間違ってやっているのか分からない

src\Main.hs:23:7: 
    Couldn't match type `Integer' with `Integer -> Integer' 
    Expected type: Integer -> (Integer -> Integer) -> Integer 
     Actual type: Integer -> Integer -> Integer 
    In the first argument of `(.)', namely `add' 
    In the expression: add . sub 

src\Main.hs:23:13: 
    Couldn't match type `Integer -> Integer' with `Integer' 
    Expected type: (Integer -> Integer) -> Integer 
     Actual type: Integer -> Integer -> Integer 
    Probable cause: `sub' is applied to too few arguments 
    In the second argument of `(.)', namely `sub' 
    In the expression: add . sub 

は、ここに私の実際のエラーコードです。

このエラーをもう少し理解して解決策を見つけることができますか?

+5

あなたは「それは意味をなさない」という点では正しい - 数学でバイナリ関数を構成するという概念はない。意味をなさないようにするには、最初に「加算」と「減算」の意味を定義する必要があります。 – molbdnilo

+0

fooの型は、加算と減算の構成は2つの*関数*( 'Integer - > Integer')をとり、整数を返す関数であると言います。 – molbdnilo

答えて

6

は、(あなたは私がセクションを理解何で自分を指摘したように)それが右に型シグネチャの仲間で->は、上記のタイプが同じである。すなわちことを覚えておくと便利です機能

add :: Integer -> Integer -> Integer 

を考えます

add :: Integer -> (Integer -> Integer) 

として、(.)の種類を検討10

これは(.)のタイプにおける発現

(.) add 

bIntegerあることを意味するとcInteger -> Integerに相当します。あなたは今sub(.) addを適用する場合は、これを書くための別の方法は、

b ~ Integer 
c ~ Integer -> Integer 

だから我々は

(.) add :: (a -> Integer) -> a -> (Integer -> Integer) 

を取得され、コンパイラはa -> IntegerInteger -> Integer -> Integerを一致させることができないことに気付きます。2はsubを適用すると、その結果はその後である - 一緒に第三引数に - addに渡さ:

は、私はあなたがおそらく組成物はの引数を取るようにしたいと思われます。だから、二つの機能が、それは価値がある何のため

foo :: (Integer -> Integer -> Integer) -> (Integer -> Integer -> Integer) -> Integer -> Integer -> Integer 
foo f g x y = f (g x y) y 

だろう構成可能な定義は、関連する問題があります:例えば、一つの引数の機能を持つ2つの引数の機能を構成します

+0

foo f g x y = f(g x y)yは、foo = liftM2(。)に短くすることができます。 –

4

私はそれらを構成したいと思っています。何の意味もありませんが、学習目標です。

これは実際問題です。どのようにそれらを構成したいですか?私たちはいくつかの可能な組成物を見てみましょう:

foo x y = sub x (add x y)   -- x + y - x = y 
foo x y = sub y (add x y)   -- x + y - y = x 
foo x y = sub x (add y y)   -- 2 * y - x 
foo x y = sub y (add y y)   -- 2 * y - y = y 
foo x y = sub y (sub y (add x x)) -- 2 * x - 2 * y 

言われていること、私たちは手からの種類をチェックすることにより、型エラーを調べてみましょう:

type I = Integer -- otherwise the lines are going to be very long 

(.)   :: (b -> c ) -> (a -> b ) -> a -> c 
add   :: I -> (I -> I) 
sub   ::     I -> (I -> I) 
--        ||||||||||||| 
(.) add  ::     (a -> I ) -> a -> (I -> I) 
--        ^^^^^^^^^^^^^ 

あなたが見ることができるように、(.) addがすでにあることを義務付け他の関数は任意のaに対してタイプa -> Integerしか持たないかもしれません。しかしsubのタイプはInteger -> (Integer -> Integer)です(覚えておいてください、(->)は正しい結合です)。

これを実際に修正するにはどうすればよいですか?

foo :: (Integer -> Integer) -> (Integer -> Integer) -> Integer 

実際に機能の非常に興味深いタイプです:まず、私たちはfooのご提案種類を調べてみましょう。どのように実際にあなたの結果を得るだろうか?あなただけの手で二つの機能を持っていませんが、何の値だ:

> foo f g = 

あなたは機能の一つの固定点を使用することによってこの問題を解決し、他を適用することができます。

> let x = f x in g x 
> 
> example = foo (const 12) (+1) -- returns 13 

しかし、それはですあなたが意味するものではない、そうですか?この時点で、作曲のセマンティクスについて考えることは非常に重要です。これらは明確ではないので、ここで両方の機能を構成する一般的な方法を書くことはできません。あなたはが実際に

foo :: Integer -> Integer -> Integer -> Integer 
foo x y z = add (sub x y) z 

を意味している場合

しかし、その後、それは

(.) add  :: (a -> I) -> a -> (I -> I) 
(.) ((.) add) :: (a -> b -> Integer) -> a -> b -> Integer -> Integer 

しかし(add .) . sub以来

foo = (add .) . sub 

で可能なのは、もはや目には本当に簡単ではありません。この種の機能が当初の目標であった場合は、fooのポイントワイズの定義を記述する方がよいでしょう。

関連する問題