21

ときどき、ポイントフリー スタイルを記述したり、ラムダを回避したりするために、「最後の引数を 2 回使用してください」と表現したい問題に出くわします。例えば

sqr x = x * x

次のように書くことができます

sqr = doubleArgs (*) where
   doubleArgs f x = f x x

または、この少し複雑な関数を検討してください (この質問から取得):

ins x xs = zipWith (\ a b -> a ++ (x:b)) (inits xs) (tails xs)

次のような関数があれば、このコードを無意味に書くことができます。

ins x = dup (zipWith (\ a b -> a ++ (x:b))) inits tails where
     dup f f1 f2 x = f (f1 x) (f2 x)

しかし、Hoogle で doubleArgs や dup のようなものを見つけることができないので、ここでトリックやイディオムを見逃す可能性があると思います。

4

3 に答える 3

30

からControl.Monad:

join :: (Monad m) -> m (m a) -> m a
join m = m >>= id

instance Monad ((->) r) where
    return = const
    m >>= f = \x -> f (m x) x

拡大する:

join :: (a -> a -> b) -> (a -> b)
join f = f >>= id
       = \x -> id (f x) x
       = \x -> f x x

ええ、そうですControl.Monad.join

ああ、あなたの無意味な例として、適用表記法を使用してみましたか (からControl.Applicative):

ins x = zipWith (\a b -> a ++ (x:b)) <$> inits <*> tails

(また、なぜ人々がa ++ (x:b)代わりにそんなに好きなのかわかりませんa ++ [x] ++ b...それは速くはありません-インライナーがそれを処理します-そして後者ははるかに対称的です!まあ)

于 2010-12-02T10:29:18.053 に答える
12

あなたが「doubleArgs」と呼ぶものは、より頻繁にdupと呼ばれます-それはWコンビネータ(To Mock a Mockingbirdではウグイスと呼ばれます)-「エレメンタリーデュプリケーター」です。

あなたが「dup」と呼ぶものは、実際には「starling-prime」コンビネータです。

Haskellの「コンビネータベース」はかなり小さいです。Data.Functionを参照してください。さらに、一部のApplicativeおよびMonadic操作では、ApplicativeおよびMonadの関数インスタンスによって「標準」コンビネータが追加されます(Applicativeの<*>はSスターリングコンビネータです。機能インスタンス、liftA2とliftM2はスターリングプライムです)。コミュニティではData.Functionを拡張することにあまり熱心ではないようです。そのため、コンビネータは非常に楽しいものですが、実際には、コンビネータが直接利用できない状況では、長い間好むようになりました。

于 2010-12-02T12:01:03.840 に答える
9

これが私の質問の2番目の部分に対する別の解決策です:矢印!

import Control.Arrow

ins x = inits &&& tails >>> second (map (x:)) >>> uncurry (zipWith (++))

( &&&「ファンアウト」) は引数を 2 つの関数に分配し、結果のペアを返します。>>>("and then") は、関数の適用順序を逆にします。これにより、左から右への一連の操作が可能になります。secondペアの 2 番目の部分でのみ機能します。もちろん、uncurry2 つの引数を期待する関数でペアを供給するには、最後に が必要です。

于 2011-05-25T06:55:35.053 に答える