Учитывая два списка, [a, b] и [c, d], я хотел бы получить следующий результат:
[(a,c), (a,d), (b,c), (b,d)]
Как я могу сделать это в Haskell? Есть ли встроенная функция для этого или я должен сам реализовать ее?
Учитывая два списка, [a, b] и [c, d], я хотел бы получить следующий результат:
[(a,c), (a,d), (b,c), (b,d)]
Как я могу сделать это в Haskell? Есть ли встроенная функция для этого или я должен сам реализовать ее?
[ (x,y) | x<-[a,b], y<-[c,d] ]
На самом деле это не требует никаких дополнительных объяснений, не так ли?
Аппликационный стиль полностью!
λ> :m + Control.Applicative
λ> (,) <$> ['a','b'] <*> ['c','d']
[('a','c'),('a','d'),('b','c'),('b','d')]
(Я избегал синтаксического сахара String выше, чтобы оставаться рядом с вашим примером.)
Для информации (,) является специальным синтаксисом для функции, которая принимает два аргумента и выдает пару из них:
λ> :t (,)
(,) :: a -> b -> (a, b)
Изменить: как отмечено leftaroundabout в его комментарии, вы также можете использовать liftA2
λ> :m + Control.Applicative
λ> let combine = liftA2 (,)
λ> combine "ab" "cd"
[('a','c'),('a','d'),('b','c'),('b','d')]
Как вы можете сделать это в императивном псевдокоде?
for each element x in [a,b]:
for each element y in [c,d]:
produce (x,y)
В Haskell это записывается как
outerProduct xs ys =
do
x <- xs -- for each x drawn from xs:
y <- ys -- for each y drawn from ys:
return (x,y) -- produce the (x,y) pair
(следующие комментарии leftaroundabout), это, конечно, очень близко к тому, как определяется liftM2 монадический комбинатор, так что фактически
outerProduct = liftM2 (,)
что совпадает с liftA2 (,), и его различные повторные записи в терминах понятий списка, concatMap function, >>=, <$> и <*>.
Концептуально, хотя это материал Applicative – который будет лучше назван Pairing, – потому что это сопряжение элементов двух "контейнеров" & frasl; "носители" и frasl; независимо от того, что такое Аппликативный Фанктор. Так получилось, что нотация Haskell do работает для монадов, а не (пока) для аппликаций.
В некотором смысле вложенные петли во время компиляции являются Applicative & frasl; Сопрягающие функции; Монады добавляют возможность создавать вложенные петли "на лету" в зависимости от значений, создаваемых "внешним" перечислением.
Наиболее интуитивно понятным будет использование понимания списков, другие аспекты включают использование аппликативных функторов:
(,) <$> [1,2,3] <*> [4,5,6]
Итак, что это делает?
Помните, что (,) :: a -> b -> (a, b) Принимает два аргумента и возвращает кортеж.
<$> acctally fmap, (<$>) :: Functor f => (a -> b) -> f a -> f b
Он выполняет функцию и поднимает ее. В этом случае требуется (,) и поднять его для работы над списком. Таким образом, let x = (,) <$> [1,2] будет генерировать x :: [b -> (Integer, b)], который является списком функций, который принимает b и возвращает кортеж с одним фиксированным аргументом (Integer, b). Наконец, мы применяем его, используя <*>, чтобы сгенерировать все комбинации.
Использование List List:
s = [a,b]
s' = [c,d]
all_combinations = [(x,y) | x <- s, y <- s']