2011-12-11 10 views
10

私は関数をHaskellのポイントフリー表記に変換する方法を理解しようとしています。私はthis exampleを見ましたが、それは私が探しているものよりも複雑です。私はその背後にあるロジックを理解しているように感じますが、コードで簡単な例を実行しようとすると、コンパイルエラーが発生します。私がしようとするとポイントフリースタイルでこの機能を書きたい:単純なHaskellはポイントフリースタイルで機能します

f x = 5 + 8/x私はそうf x = (+) 5 $ (/) 8 x

として再配置、私はそれがこのようなものかもしれないと思った:

f = (+) 5 $ (/) 8 

が、私は実行するとこれは、GHCiの中で私はこのメッセージが表示されます。

No instance for (Num (a0 -> a0)) 
    arising from the literal `5' at Test.hs:3:9 
Possible fix: add an instance declaration for (Num (a0 -> a0)) 
In the first argument of `(+)', namely `5' 
In the first argument of `($)', namely `(+) 5' 
In the expression: (+) 5 $ (/) 8 
Failed, modules loaded: none. 

私はメッセージ「のために...いいえ、インスタンスを」理解していません。この機能をポイントフリーのスタイルで書くには、何が必要ですか?

+3

私はhttp://stackoverflow.com/questions/940382/haskell-difference-between-dot-and-dollar-sign(あなたは[ '$'と '.'事業者との違い]について混乱かもしれないと思います)。 – hammar

答えて

16

$の優先度は非常に低くなります。したがって、f x = (+) 5 $ (/) 8 xは実際にはf x = (+) 5 $ ((/) 8 x)を意味します。 fは、二つの動作の組成が何であるか一つ最初の分割8を有し、その結果に5を追加します。その代わりに、

f x = (+) 5 ((/) 8 x) 
f x = ((+) 5) (((/) 8) x) 
f x = ((+) 5) . (((/) 8)) x 
f = ((+) 5) . ((/) 8) 
f = (5+) . (8/) 

として最後の式は、理にかなっていることを書き換え覚えておいてください、 g.hは "apply h、その後gの結果を適用する"という意味です。

+0

はい、今感謝します、ありがとう! – KJ50

+0

これは実際には素晴らしいことです:3つのupvoted答えすべては、質問の異なる角度を示しています。 –

10

"pointfree"プログラムはcabal install pointfreeと一緒にインストールすることができ、式をポイントフリースタイルで書く方法を示します。たとえば、次のようにこの変換の

$ pointfree "f x = 5 + 8/x" 
f = (5 +) . (8 /) 

は説明:

  1. あなたは中置/オペレータの機能のための "セクション" を使用することができます。 (a +) == \b -> a + bおよび(+ a) == \b -> b + a
  2. .関数は、1引数の関数である2番目のパラメータの結果を受け取り、1番目の引数に適用します。
+0

ポイントフリースタイルを使用したいのはなぜですか? 1.私は私の機能を簡単にすることを強制していますので、私は実際にコードの重複を減らすこと、既に書かれた関数を再利用する気だろう大きなチャンスがあります。2.それらをより再利用可能な作り: –

+0

私は個人的にので、pointfreeスタイルを使用して自分自身を強制します。 – dflemstr

+1

(。)は連想的ですが、($)はそうではないので、(。)はリファクタリングの柔軟性を高めます。そして、あなたはポイントフリーのスタイルをマスターする必要があります。また、liftM2、fmap、>> =、> =>のようなモナドコンビネータは、ほとんどあなたがポイントフリーのスタイルを学ばなければなりません。 – nponeccop

4

あなたは本当に近くでした。私が説明するために$ 1以上を追加することを許可する:

f x = (+) 5 $ (/) 8 $ x 

表現(+) 5が1つの数値入力を受け取り、数値の出力を生成機能であることは明らかです。式は(/) 8と同じです。したがって、入力された数字が何であっても、xとし、最初に(/) 8「関数」を適用してから、(+) 5「関数」を適用します。あなたは$で区切られた機能の鎖を持つたび

することは、あなたがa $ b $ c $ dを持っている場合、これはa . b . c $ dに相当し、.意味で、右端を除くすべてを置き換えることができます。この時点で

f x = (+) 5 . (/) 8 $ x 

、のは、実際に$を削除し、代わりに括弧しましょう。

f x = ((+) 5 . (/) 8) x 

今、あなたが両側から末尾のxを削除することができることは明らかである:

f = (+) 5 . (/) 8 

が主要なアイデアであること。 f x = expr xがある場合は、f = exprに「ηを減らす」ことができます。ポイントフリーのコードを生成するには、より大きな関数がどのように小さな関数で構成されているかを簡単に認識する必要があります。ポイントフリーコード(この場合、(+) 5および(/) 8が部分的に適用されているように)に部分的なアプリケーションが必要な場合があります。 「ポイントフリー」プログラムは、あなたがそれについて考えたくないときには非常に役に立ちます。 #haskell ircチャンネルのLambdabotはこのプログラムをプラグインとして使用しているので、自分でインストールする必要はありません。ただ尋ねる:のみconstKを使用して、(完全pointfree機能を用語をスキー用語(Haskellはの変形である)ラムダ計算)から

<DanBurton> @pl let f x = 5 + 8/x in f 
<lambdabot> (5 +) . (8 /) 
10

変換、idI)と<*>S))は、以下の簡単なルールで行うことができる。

  1. \x -> xidに変換します; yconst yに変換で発生x無し
  2. \x -> y
  3. \x -> f g
    • f'\x -> f
    • g'の翻訳である\x -> gの翻訳であるf' <*> g'に変換されます。

.がでてくるんどこ今、あなたは不思議に思うことがあり、最後の翻訳の特殊なケースがあります:。fxの任意の自由な出現を持っていない場合は、\x -> f gは等しくなる、const f <*> (\x -> g)に変換f . (\x -> g)

f = \x -> ((+) 5) (((/) 8) x) = -- by the special-case (.) rule 
((+) 5) . (\x -> (((/) 8) x)) = -- by eta-reduction ((\x -> f x) = f) 
((+) 5) . ((/) 8) 

イータ減少が翻訳を完了する必要はありませんが、それなしで、我々は何かのメシエを取得したい:私たちはあなたの関数を変換することができ、これらのルールを使用して

。たとえば、最後のステップでは代わりに((+) 5) . ((/) 8) . idが返されます。

関連する問題