Учитывая два списка, [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']