我是Haskell的新手,并且对如何以最惯用和最清晰的方式表达一些操作感到困惑.目前(还会有更多)我很困惑<*>(我甚至不确定该怎么称呼).
例如,如果我有,比方说
f = (^2)
g = (+10)
Run Code Online (Sandbox Code Playgroud)
作为代表性的功能(实际上它们更复杂,但关键在于它们是不同的和不同的),然后
concatMap ($ [1,2,3,4,10]) [(f <$>), (g <$>) . tail . reverse]
Run Code Online (Sandbox Code Playgroud)
和
concat $ [(f <$>), (g <$>) . tail . reverse] <*> [[1,2,3,4,10]]
Run Code Online (Sandbox Code Playgroud)
完成同样的事情.
是其中一个更惯用的Haskell,是否有人暗示Haskell经验丰富的读者,而另一个则不然.也许有更多(更好)的方式来表达完全相同的东西.这两种方法之间是否存在概念上的差异,像我这样的新手Haskeller可能会丢失?
Lee*_*Lee 10
无论你的函数(f <$>),并(g <$>).tail.reverse(在这种情况下列表)返回一个独异类型,这样就可以使用mconcat,将它们转换成一个单一的功能.然后,您可以将此函数直接应用于输入列表,而不是将其包装在另一个列表中并使用concatMap:
mconcat [(f <$>), (g <$>).tail.reverse] $ [1,2,3,4,10]
Run Code Online (Sandbox Code Playgroud)
为了对此进行扩展,函数a -> b是Monoidif 的实例b是monoid.在实施的mappend这种功能是:
mappend f g x = f x `mappend` g x
Run Code Online (Sandbox Code Playgroud)
或者等价的
mappend f g = \x -> (f x) `mappend` (g x)
Run Code Online (Sandbox Code Playgroud)
所以给定两个函数f并g返回一个monoid类型b,fmappend g返回一个函数,该函数将其参数应用于f和g并使用Monoid实例组合结果b.
mconcat具有类型Monoid a => [a] -> a并使用输入列表的所有元素组合mappend.
列表是monoids,其中mappend== (++)so
mconcat [(f <$>), (g <$>).tail.reverse]
Run Code Online (Sandbox Code Playgroud)
返回一个类似的函数
\x -> (fmap f x) ++ (((fmap g) . tail . reverse) x)
Run Code Online (Sandbox Code Playgroud)
就个人而言,我会写
f = (^2)
g = (+10)
let xs = [1,2,3,4,10]
in (map f xs) ++ (map g . tail $ reverse xs)
Run Code Online (Sandbox Code Playgroud)
在一个非常应用型"心情",我将取代后的部分in由
((++) <$> map f <*> map g . tail . reverse) xs
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我实际上并不认为它更具可读性.如果您不直接了解它的含义,请花一些时间来理解()的Applicative实例.((->) a)Reader
我认为这个选择实际上取决于你想要做什么,即你的输出意味着什么.在您的示例中,任务是非常抽象的(基本上只是展示了Applicative可以做什么),因此使用哪个版本并不明显.
直观的Applicative实例[]与组合有关,所以我会在这样的情况下使用它:
-- I want all pair combinations of 1 to 5
(,) <$> [1..5] <*> [1..5]
Run Code Online (Sandbox Code Playgroud)
如果你有很多函数,并且你想要尝试使用多个参数的这些函数的所有组合,我确实会使用.的[]实例Applicative.但是,如果你所追求的是不同变换的串联,我会这样写(我在上面做过).
仅仅是我2美分作为中等体验的Haskeller.