Карта Haskell / zip Vs.понимание списка - PullRequest
19 голосов
/ 04 июля 2010

Что из нижеперечисленного вы, скорее всего, напишите?

r = zip xs $ map sqrt xs

или

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

Пример кода в Интернете, кажется, указывает на то, что первый код более распространен и предпочтителенспособ.

Ответы [ 7 ]

25 голосов
/ 04 июля 2010

Люди, которые проводят слишком много времени в #haskell, вероятно, написали бы это как

r = map (id &&& sqrt) xs

(&&&) - забавный комбинатор, определенный в Control.Arrow. Его фактическая типовая сигнатура сложна, потому что она обобщена на все экземпляры Arrow. Но он часто используется с (->) экземпляром Arrow, что приводит к подписи этого типа:

(&&&) :: (a -> b) -> (a -> c) -> a -> (b, c)
16 голосов
/ 04 июля 2010

Хотя я склонен не использовать их очень часто, в этом случае, я думаю, я бы предпочел версию со списком, поскольку она кажется мне чище.

Если вы любите стиль без точек, он вам тоже может понравиться:

f = zip `ap` map sqrt

ap живет в Control.Monad, и в этом случае его можно рассматривать как комбинатор S, который обобщает применение в исчислении SKI :

ap f g x == f x (g x)
ap const const == id

Как указывает Конал, это также может быть обобщено от Monad к Applicative таким образом (import Control.Applicative):

f = zip <*> map sqrt
12 голосов
/ 05 июля 2010

Я бы, вероятно, написал map / zip, а потом хотел бы, чтобы я написал список для понимания.

10 голосов
/ 08 июля 2010

Скорее всего, я напишу

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

Если вы предпочитаете бессмысленно, вышеприведенное эквивалентно (после импорта Control.Monad и Control.Monad.Instances)

map (ap (,) sqrt) xs

Еще одна альтернатива, которая еще не упоминалась, это

zipWith (,) xs (map sqrt xs)
10 голосов
/ 05 июля 2010

Для определенных типов проблем (в частности, Project Euler ) этот частный случай возникает так часто, что я написал следующий маленький помощник:

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

Это позволяет написать ваш пример:

r = map (with sqrt) xs
7 голосов
/ 05 июля 2010

Я больше из Хаскелье из "Старой школы", поэтому я бы использовал zip `ap` map sqrt, а затем реорганизовал его, чтобы использовать <*> вместо ap.

Аппликативной является новая Монада. (В смысле «что используют Cool Haskell Kids в наши дни?»)

6 голосов
/ 04 июля 2010

Я редко использую списочные выражения, но оба они денди.Просто используйте тот, который облегчает чтение вашего кода.

...