2015-09-30 137 views
14

我與別人的堆棧溢出的問題,一個簡單的函數玩耍,並寫下了表達(與應用型((>)T),也許?):刪除重複數據刪除 -

f a x ++ f a y 

顯然,這是在現實生活中編寫這個表達式的最好方法,因爲我已經有了所有這些變量,但是我看到了f a的重複,並且認爲「嘿,也許你可以用Applicative實例去除那些函數」。我結束了:

liftA2 (++) (flip f x) (flip f y) a 

這只是可怕的。是否有更好的方法來消除這種重複?顯然,我也可以通過將f a綁定到where子句中的某些東西來刪除重複內容,但這是爲了使用內置函數的練習。

回答

21

你可以做

((++) `on` f a) x y 

不使用Applicative,但(對不起)。

+0

我喜歡這個答案,雖然!我想我並沒有真正在尋找Applicative的答案,以至於如何使用標準庫去除重複。 – amalloy

21

[......]也許你可以用Applicative實例刪除函數。

您是否必須使用((->) t)Applicative實例?如果你只是想擺脫重複的f a,爲什麼不使用列表monad,而是?

[x, y] >>= f a 

,或者等價地,

f a =<< [x, y] 

例子:

λ> let f :: Int -> Int -> [Int]; f a x = [a .. x] 

λ> f 1 2 ++ f 1 3 
[1,2,1,2,3] 

λ> [2, 3] >>= f 1 
[1,2,1,2,3] 

λ> f 1 =<< [2, 3] 
[1,2,1,2,3] 
+0

值得注意的是''= <<'在這種情況下與'concatMap'相同,所以如果你想根據列表操作而不是monad來思考這個,那就是要使用的函數。 –

+0

@ cool_me5000當然,但我想強調操作的monadic方面。 – Jubobs

14

Bikeshedding的樂趣!另一種選擇是使用Monoid實例功能:

(($x) <> ($y)) (f a) 
+1

我不明白這一個。是不是'mappend'組成,爲功能?和'++'發生了什麼? – amalloy

+0

@amalloy對於函數,'mappend'是逐點附加的:'mappend f g x = mappend(f x)(g x)'。 '(++)'消失了,因爲它是每個點發生的'mappend'。 –

3

由於問題暗示使用應用型解決方案(雖然其他的答案是更優雅)...

((++) <$> ($ x) <*> ($ y)) (f a) 
+0

如果你想擺脫一些括號,你可以寫:'(++)<$>($ x)<*>($ y)$ f a'。 – Jubobs

+1

@Jubobs我不確定他是否正確,但我已經決定對Gabriel Gonzalez的建議進行道路測試,以使Haskell代碼更易於被非Haskellers讀取:http://www.haskellforall.com/2015/09 /how-to-make-your-haskell-code-more.html。避免使用'($)'是他的首要建議。 – frasertweedale

+0

感謝鏈接':)' – Jubobs