2012-07-29 63 views
25

我有一天很無聊,想鍛鍊我的大腦,所以我決定去做99 Haskell Problems,但我限制自己以無點式的方式做。當我以無點式的方式做事情時,似乎出現了很多問題:如何將多個函數應用於相同的值,同時將每個結果保留爲獨立的實體?使用尖銳的表示法:在Haskell中將多個函數應用於相同的無值點式樣

foobar x = [id x, reverse x] 

什麼,我拿出迄今無點符號:

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

我似乎無法得到那個x過那裏的結束。

回答

25

其他人已經發布瞭如何可以使用Reader單子做到這一點,但是這不是唯一的方法。事實證明,你的第二個功能非常接近。我覺得你的意思後

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 

改寫這個應用程序作爲一個功能組成,然後你就可以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) 

最後,請注意,我們可以用函數替換lambda表達式

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

並且您有一個無點形式。

8

你會感興趣的讀者單子的Applicative實例:

instance Applicative (e ->) 

使用它可以輕鬆地分發參數:

liftA2 (+) sin cos 3 

這裏sincos的功能,既接收值3.然後使用(+)組合各個結果。您可以進一步將此與(->)Category實例組合,但(.)id的源專用版本已在Prelude中定義。

背景:Applicative實例(e ->)真正代表了SKI演算,其中(<*>)小號組合子和pureķ組合子。 小號被精確地用於一個參數分配到兩個功能:

S f g x = f x (g x) 

它需要一個功能應用(FG)和使得無論依賴於值X(FX)(GX) )。

9

使用sequence

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

只有當你確定與約束。這不適用於所有用途。 – 2012-07-29 14:43:20

+0

@ ThomasM.DuBuisson:什麼約束? – 2012-08-09 14:30:44

+0

@BenMillwood我指的是typeclass約束。 JohnL的答案是'a - > [a]'類型。這個答案雖然很好乾淨,但是類型爲Monad(( - > a)=> a - > [a]' – 2012-08-09 15:57:47

5

有幾個基本的慣用combinators反覆彈出,並重新實現了各種高級概念和庫,但實質上非常簡單。名稱可能會有所不同,而在其他方面有些是可實現的:

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定義,以及firstsecond。然後prod (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) 

對於您還需要導入Control.MonadControl.Monad.Instances最後一個。另見this question


後期編輯:此外,使用Control.Applicativeertes回答暗示,

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

也可以,'(:) <*>(純粹的反向)'((( - >)r),[ (' - ] r)'Monad'),'([id,reverse]')。 – 2016-04-23 20:08:09

相關問題