你最可能写哪种代码?
r = zip xs $ map sqrt xs
或者r = [(x, sqrt x) | x <- xs]
互联网上的示例代码似乎表明前者更常见且更受欢迎。
你最可能写哪种代码?
r = zip xs $ map sqrt xs
或者r = [(x, sqrt x) | x <- xs]
互联网上的示例代码似乎表明前者更常见且更受欢迎。
在 #haskell 里花费过多时间的人可能会将其写成:
r = map (id &&& sqrt) xs
(&&&)
是在 Control.Arrow
中定义的有趣组合子。它的实际类型签名很复杂,因为它被泛化到了 Arrow 的所有实例上。但它经常与 (->)
的 Arrow 实例一起使用,从而产生了下面的类型签名:
(&&&) :: (a -> b) -> (a -> c) -> a -> (b, c)
尽管我通常不太经常使用它们,但在这种情况下,我认为我更喜欢列表推导式的版本,因为它看起来更简洁。
如果你喜欢点-自由风格,你也可能会喜欢这个:
f = zip `ap` map sqrt
ap
函数位于Control.Monad中,在这种情况下,它可以被认为是S组合子,该组合子在SKI演算中概括了应用:
ap f g x == f x (g x)
ap const const == id
正如Conal所指出的那样,这也可以从Monad推广到Applicative,因此(import Control.Applicative
):
f = zip <*> map sqrt
ap
读作“应用”,所以它变成了:“将zip、apply和map与sqrt一起应用到输入”。 - Danmap (id &&& sqrt) xs
。 - Conal我可能会写 map
/zip
,但后来希望我写了列表推导式。
我可能会写成
map (\x -> (x, sqrt x)) xs
如果您喜欢使用点符号风格,上述内容等价于(在导入Control.Monad
和Control.Monad.Instances
后):
map (ap (,) sqrt) xs
还有一个尚未提到的替代方案是
zipWith (,) xs (map sqrt xs)
对于某些问题(特别是欧拉计划),这种情况经常出现,我编写了以下小助手:
with :: (a -> b) -> a -> (a,b)
with f a = (a, f a)
这样可以让你的示例被写成:
r = map (with sqrt) xs
我更倾向于使用“老派”的Haskell方法,所以我会使用zip `ap` map sqrt
,然后稍后重构它以使用<*>
而不是ap
。
Applicative是新的Monad。(在“Cool Haskell Kids现在使用什么?”的意义上)
我很少使用列表推导式,但两者都很好用。只需使用使您的代码更易于阅读的那个。
&&&
的含义,但那很有趣 :-). - mk12