2010-12-02 24 views
19

偶爾我會偶然發現我想表達的問題,「請使用最後一個參數兩次」,例如爲了寫無點式或避免lambda。例如。欺騙「重複使用」參數在Haskell中?

sqr x = x * x 

可以寫成

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

或者考慮這個稍微複雜功能(從this question拍攝):如果有類似的功能

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

我可以寫這個代碼pointfree此:

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的東西,所以我想我可能會在這裏錯過一個技巧或習慣用法。

回答

26

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

哦,你pointfree例如,你有沒有嘗試過使用應用性符號(從Control.Applicative):

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

(我也不知道爲什麼人們這麼喜歡a ++ (x:b)代替a ++ [x] ++ b ...它不是更快 - 內聯會照顧它 - 而後者是更對稱的!哦)

+2

而根據`pointfree`,`dup`可以算作'liftM2`。我真的需要更好地處理函數的monad實例。 – 2010-12-02 10:30:43

+2

謝謝你們提供甚至**兩種**方法來解決這些問題。順便說一句我試過`sqr =(*)<$> id <*> id`,它也適用:-) – Landei 2010-12-02 10:57:34

11

你稱爲'doubleArgs'更經常被稱爲dup - 它是W combinator(稱爲鶯在模仿一隻知更鳥) - 「基本複印機」。

你所說的'dup'其實就是'starling-prime'組合子。

Haskell具有相當小的「組合基礎」參見Data.Function,再加上一些Applicative和Monadic操作,通過Applicative和Monad的函數實例添加更多「標準」組合器(Applicative的< *>是S - starling combinator爲功能實例,liftA2 & liftM2是starling-prime)。在擴展Data.Function的時候,社區似乎沒有太多的熱情,所以雖然combinator是好玩的,但實際上我更喜歡在combinator不直接可用的情況下長期使用。

7

這是我的問題的第二部分的另一個解決方案:箭頭!

import Control.Arrow 

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

&&&(「扇出」)分配一個參數兩個功能,並返回對結果。 >>>(「然後」)反轉功能應用程序的順序,從而允許從左到右具有一系列操作。 second只適用於一對的第二部分。當然,你最後需要一個uncurry來爲一對函數提供兩個參數。