20

您最有可能写以下哪项?

r = zip xs $ map sqrt xs

或者

r = [(x, sqrt x) | x <- xs]

网上的示例代码似乎表明前者更丰富,是首选方式。

4

7 回答 7

27

在#haskell 上花费太多时间的人可能会这样写

r = map (id &&& sqrt) xs

(&&&)是一个有趣的组合器,定义在Control.Arrow. 它的实际类型签名很复杂,因为它被推广到 Arrow 的所有实例。但它经常与 的(->)实例一起使用Arrow,这会导致这种类型签名:

(&&&) :: (a -> b) -> (a -> c) -> a -> (b, c)
于 2010-07-04T18:22:27.500 回答
17

虽然我倾向于不经常使用它们,但在这种情况下,我认为我更喜欢列表理解版本,因为它对我来说似乎更干净。

如果你喜欢无点风格,你可能也会喜欢这个:

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 (导入 Control.Applicative):

f = zip <*> map sqrt
于 2010-07-04T18:23:27.053 回答
13

我可能会写map/zip然后希望我已经写了列表理解。

于 2010-07-05T02:50:06.230 回答
11

对于某些类型的问题(尤其是Project Euler),这种特殊情况经常出现,因此我编写了以下小助手:

with :: (a -> b) -> a -> (a,b)
with f a = (a, f a)

这允许您编写示例:

r = map (with sqrt) xs
于 2010-07-05T03:46:27.543 回答
11

我可能会写

map (\x -> (x, sqrt x)) xs

如果您更喜欢无点,则以上等效于(在导入Control.Monadand之后Control.Monad.Instances

map (ap (,) sqrt) xs

另一个尚未提及的替代方案是

zipWith (,) xs (map sqrt xs)
于 2010-07-08T18:20:13.480 回答
8

我更像是一个“老派”的 Haskellier,所以我会使用zip `ap` map sqrt并稍后重构它以使用<*>而不是ap.

Applicative 是新的 Monad。(从“这些天酷 Haskell 孩子们使用什么?”的意义上说)

于 2010-07-05T05:48:45.363 回答
7

我很少使用列表推导,但两者都很花哨。只需使用使您的代码更易于阅读的那个。

于 2010-07-04T18:17:26.210 回答