2012-07-29 12 views
25

私は一日飽きて脳を鍛えたかったので、99 Haskell Problemsをやることにしましたが、ポイントフリーのスタイルでやっていました。私がポイントフリーのスタイルでやっているときに大した問題となる問題は次のとおりです。それぞれの結果を独立したエンティティとして保持しながら、同じ値に複数の関数を適用するにはどうすればよいですか?ハスケルで同じ値のポイントフリースタイルに複数の関数を適用する

foobar x = [id x, reverse x] 

そして、私はポイントなしの表記で、これまでに作ってみた:先の尖った表記を使用すると、

foobar' = `map` [id, reverse] ($ x) 

私はそこの末尾からxことを得るように見えることはできません。

liftA2 (+) sin cos 3 
ここ

sincosは、両方の受信機能、次のとおりです。あなたは簡単に引数を配布することができ、それを使用して

instance Applicative (e ->) 

答えて

25

その他は、すでにあなたがReaderモナドを使ってこれを行うことができますどのように掲載されているが、それは唯一の方法ではありません。あなたの2番目の機能はかなり近いことが判明しました。私はあなたがxは右端の位置の近くに、あなたはほとんどそこにいるすでにあるので

foobar' x = (`map` [id, reverse]) ($ x) 

を投稿するためのものだと思います。まず、それはで動作するように少し簡単だから、関数にセクション($ x)変換:

-- by the definition of a right operator section 
foobar'2 x = (`map` [id, reverse]) (\y -> ($) y x) 

を次のスコープに新しい変数をもたらすことによって、ラムダ本体からxを削除し、x

に関数を適用します
-- lambda abstraction I think... 
foobar'2 x = (`map` [id, reverse]) $ (\z y -> ($) y z) x 
は、関数組成物として、このアプリケーションを書き換え

、その後、あなたはETAは減らすことができます。

-- by definition of '.' 
foobar'3 x = (`map` [id, reverse]) . (\z y -> ($) y z) $ x 

-- eta reduction 
foobar'4 = (`map` [id, reverse]) . (\z y -> ($) y z) 

最後に、ラムダを関数に置き換えることができることに注意してください。

-- by definition of `flip` 
foobar'5 = (`map` [id,reverse]) . flip ($) 

あなたはポイントフリーの形式です。

8

あなたはリーダーモナドのApplicativeインスタンスに興味があるだろう値は3となります。個々の結果は、(+)を使用して結合されます。これをさらにCategoryのインスタンス(->)と組み合わせることができますが、(.)idのソース専用バージョンのものはPreludeに既に定義されています。

背景:(e ->)ためApplicativeインスタンスが本当に(<*>)SコンビネータとpureKコンビネータであるSKIの計算を表します。それは値X(FX)(GX)に依存両方機能アプリケーション(FG)をとり行う

S f g x = f x (g x) 

S正確二つの関数の引数を配布するために使用されています)。

9

使用sequence

> let foobar' = sequence [id, reverse] 
> foobar' "abcde" 
["abcde","edcba"] 
+0

。これはすべての用途では機能しません。 –

+0

@ ThomasM.DuBuisson:どのような制約? –

+0

@BenMillwood私はtypeclassの制約について言及しています。 JohnLの答えは 'a - > [a]'です。 –

5

いくつかの基本的な慣用的なコンビネータが繰り返しポップアップし、より高いコンセプトとライブラリで再実装されていますが、基本的には非常に簡単です。名前は変更される場合があり、一部は他の面で実装可能です:

はもちろん uncurry f (x,y) == f x y
fork (f,g) x = (f x, g x)    -- == (f &&& g) 
prod (f,g) x = (f $ fst x, g $ snd x) -- == (f *** g) 
pmap f (x,y) = (f x, f y)    -- == (f *** f) 
dup  x = (x,x) 

なども、これらとの多くを使用します。

&&&***Control.Arrow、ならびにfirstsecondで定義されています。その後prod (f,id) == first fprod(id,g) == second gなどなど

だからあなたfoobarはあなたにもControl.MonadControl.Monad.Instancesをインポートする必要があり、最後の1については

foobar = (\(a,b)->[a,b]) . fork (id,reverse) 
     = (\(a,b)->[a,b]) . (id &&& reverse) 
     = (\(a,b)->[a,b]) . (id *** reverse) . dup 
     = join $ curry ((\(a,b)->[a,b]) . second reverse) 

になります。 this questionも参照してください。


後半編集:またertesでの回答で示唆したようControl.Applicative使用して、あなたが制約とOKしている場合のみ

 = (:) <*> ((:[]) . reverse) 
+0

'(:) <*>(純正逆) '('(( - >)r)、[純粋な '' []]適用、 ''シーケンス[id、逆] ''(( - >)r) 'モナド) –

関連する問題