30

ある日退屈して脳を鍛えたかったので、99のHaskell問題をやろうと決心しましたが、ポイントフリースタイルでやることに制限しました。ポイントフリースタイルで作業しているときによく発生する問題は、次のとおりです。各結果を独立したエンティティとして保持しながら、同じ値に複数の関数をどのように適用しますか?先のとがった表記の使用:

foobar x = [id x, reverse x]

そして、私がこれまでにポイントフリー表記で思いついたもの:

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

x私はそこの終わりからそれを取り除くことができないようです。

4

4 に答える 4

28

Readerモナドを使用してこれを行う方法をすでに投稿している人もいますが、それが唯一の方法ではありません。2番目の関数はかなり近いことがわかります。投稿するつもりだったと思います

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

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

このアプリケーションを関数合成として書き直すと、次のように減らすことができます。

-- 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 ($)

そして、あなたはポイントフリーのフォームを持っています。

于 2012-07-29T13:43:56.700 に答える
16

Applicativeリーダーモナドのインスタンスに興味があります。

instance Applicative (e ->)

これを使用すると、引数を簡単に配布できます。

liftA2 (+) sin cos 3

ここsinにとcosは関数であり、どちらも値3を受け取ります。次に、個々の結果がを使用して結合され(+)ます。Categoryこれをのインスタンスとさらに組み合わせることができます(->)が、コースに特化したバージョンの(.)idはすでにで定義されていPreludeます。

背景:のApplicativeインスタンスは、(e ->)実際にはSKI計算を表します。ここ(<*>)で、はSコンビネータ、pureKコンビネータです。 Sは、引数を2つの関数に分散するために正確に使用されます。

S f g x = f x (g x)

関数適用(fg )を取り、両方を値x(fx)(gx) )に依存させます。

于 2012-07-29T12:53:56.623 に答える
15

シーケンスを使用:

> let foobar' = sequence [id, reverse]
> foobar' "abcde"
["abcde","edcba"]
于 2012-07-29T13:10:12.053 に答える
5

繰り返しポップアップし、さまざまなより高度な概念とライブラリで再実装される、いくつかの基本的な慣用的なコンビネータがありますが、これらは本質的に非常に単純です。名前は異なる場合があり、他の観点から実装可能なものもあります。

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)

もちろんuncurry f (x,y) == f x y、これらにもよく使われます。

&&&およびは、、および***で定義されControl.Arrowます。その後、などなど。firstsecondprod (f,id) == first fprod(id,g) == second g

だからあなたfoobar

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)

最後の1つについては、インポートする必要がありControl.MonadますControl.Monad.Instancesこの質問も参照してください。


後期編集:また、ertesControl.Applicativeによる回答で示唆されているように使用して、

       = (:) <*> ((:[]) . reverse)
于 2012-07-29T13:56:35.627 に答える