2015-09-30 133 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