2017-05-07 9 views
0

私はハスケル型の演習をしていましたが、これは私を困惑させました。提供式は次のとおりです。この式のハスケル型を理解する

f2 f g h = h.g.f 

とF2のための型が明らかである:これは、このような短い表現のために過度に複雑そうです

f2 :: (a -> b1) -> (b1 -> b) -> (b -> c) -> a -> c 

。誰かがこれがなぜ型として理にかなっているのか説明できますか?

答えて

3

は、なぜあなたはそれが複雑だと思いますか?それは、(一致する型の)3つの関数を取り、新しい関数を返す関数です。

私はbからb1と改名しましたし、一貫性のために、他の名前を更新しました。

f2 :: (a -> b) -> (b -> c) -> (c -> d) -> a -> d

ここ
  • f2がかかるfa -> bを入力していますので、ここで少し編集されたバージョンです。つまり、それはいくつかのタイプaのいくつか入力して、機能だとタイプbのいくつかの戻り値(aは何でも、ここでは制限が可能)。
  • f2gとなります。入力のタイプはfの出力と一致する必要がありますので、b -> cです。それは、のように、することはできませんe -> cebから別の何かである場合)、またはf . gを構成することはできませんように、コードは意味がありません。
  • 第3引数の場合はhで、タイプがc -> dの場合とまったく同じです。
  • 関数の結果(f2が返す)は、fが返す値を取り込み、hが返す値を返す新しい関数なので、a -> dです。これで、型定義全体をカバーしました。

基本的には比較的長い定義ですが、非常に単純な性質だと思います。

+0

第4のポイントは私を混乱させるものです、私はそこまで理解しています。具体的には、「fが何を返しても何でも返します」 –

+0

私はもうちょっとそれを見つめていましたが、私が与えた例ではd、cがなぜそこにあるのか理解しています何故そこにいなければならないのかについてまだ混乱している。 –

+1

@KaiD:f3 f g = fというやや簡単な例を考えてみましょう。 (f→:: a - > b) - >(b - > c) - > a - > c'の形式をとる。 2つの関数( 'f'と' g')をとり、新しい関数を生成します。 'a - > c'の部分では、生成された関数の入力型は' f'と同じ型 'a'となり、戻り型は' d'で 'gと同じです'が返ってくる。たとえば、 'f'が文字列をとり整数を返し、' g'が整数をとり、ブール値を返す場合、 'f3'の結果は文字列をとりブール値を返さなければなりません。これが型宣言の意味です。意味がありますか? – drdaeman

3

Iは、これらのビット後方一般「は、そのような表現のタイプを決定する」見つけます。タイプは常に最初に来るべきです:何らかのタスクの解決策をプログラムしたい場合は、問題の説明を型シグニチャーとして定式化します。 あなたは先に進み、実際に実装を記述します。この場合

、あなたは問題を開始したい:私は、次の3つの機能fghを持っている、と私はfに渡すことができるタイプの値。さらに、これらの関数は、ペアごとに一致する結果/引数型を持ちます。したがって、署名

f2 :: (α -> β) -> (β -> γ) -> (γ -> δ) -> α -> δ 

あなたは今すぐに行くと明示尖った形でこれを実装することができ、すなわち

f2 f g h x = h (g (f x)) 

まだかなり簡単です。結局のところ、それはかなり簡単な作業です!

しかし、Haskellで、あなたは標準組成演算子.を使用することによって、それがさらに短くすることができます。最終的な実装が非常に短いという事実は、基本的には、f2が本質的に.と同じことを2回だけ実行するという事実にまさしくあります。複雑な型シグニチャを持つ非常に複雑なタスクを持っていても、ほぼ正確なタスクを行う関数を含むライブラリを発見するよりも、これは驚くことではありません。明らかに、準備完了ビルド関数を呼び出すと、タスクの複雑さよりもはるかに短い実装が得られますが、複雑さは単にライブラリ関数に任せるだけです。

+0

(b - > c)に相当するものまでお付き合いしていますが、なぜ型式がそこで終わらないのか分かりません。なぜ私は次の2つを必要とするのですか?> a> c? –

+1

@KaiD型式は戻り値をカバーするためです。 'a - > c'('α - >δ')は 'f2'が返すものの一種です。 – drdaeman