Что это значит?

В этом руководстве http://learnyouahaskell.com/starting-out автор пишет этот фрагмент кода.

boomBangs xs = [ if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x]

А затем позже выполняет это так

boomBangs[7..13]

И мой вопрос, что делает оператор "‹-"? Мне кажется, что это вызовет рекурсивное поведение, поскольку я ссылаюсь на то, что мне кажется функцией внутри функции, или, возможно, определяю, как создать понимание списка.

Поискав вокруг, я нашел это объяснение чи по другому вопросу:< br> "x ‹- действие запускает действие ввода-вывода, получает его результат и привязывает его к x"

Отличается ли «‹-» в вопросе, указанном выше, от «‹-», используемого в коде, который я скопировал выше? Запускается ли xs внутри xs? Буду признателен, если кто-нибудь объяснит мне, что здесь происходит.


person Magnar Kleppe    schedule 12.08.2019    source источник
comment
Синтаксис понимания списка — это, по сути, просто синтаксис выражения do, который является синтаксическим сахаром для некоторых выражений с привязками.   -  person Willem Van Onsem    schedule 12.08.2019
comment
xs в левой части — это аргумент функции, а в правой — фактическое определение функции. Это ничем не отличается от f x = x + 3. В этом случае оператор <- просто означает брать последовательные значения из списка xs и вызывать их каждое x по мере прохождения цикла.   -  person Andrew Jaffe    schedule 12.08.2019
comment
<- на самом деле не оператор; это просто часть синтаксиса понимания списка.   -  person chepner    schedule 12.08.2019
comment
да, ‹- в вопросе, указанном выше (часть монадического синтаксиса do-notation) is< /i> отличается от ‹-, используемого в коде (часть синтаксиса понимания списка). Нет, хз не запускается внутри хз, говорить об этом бессмысленно. xs справа от = (переменная) относится к xs слева (т.е. параметру boomBangs).   -  person Will Ness    schedule 12.08.2019
comment
Спасибо всем! Узнал много нового, спасибо!   -  person Magnar Kleppe    schedule 13.08.2019


Ответы (1)


Ваше понимание списка - это, по сути, просто синтаксический сахар для:

import Control.Monad(guard)

boomBangs :: Integral i => [i] -> [String]
boomBangs xs = do
    x <- xs
    guard (odd x)
    return (if x < 10 then "BOOM!" else "BANG!")

Таким образом, это do выражение [отчет Haskell], и как говорится в отчете, это синтаксический сахар. Это синтаксический сахар для:

boomBangs xs = xs >>= \x -> (guard (odd x) >> return (if x < 10 then "BOOM!" else "BANG!"))

Для списка экземпляр Monad определяется как:

instance Monad [] where
    (>>=) = flip concatMap
    return x = [x]

Кроме того, guard определяется как:

guard :: Monad m => Bool -> m ()
guard True = pure ()
guard False = empty

и реализация (>>) по умолчанию:

(>>) :: Monad m => m a -> m b -> m b
(>>) u v = u >>= \_ -> v

Таким образом, boomBangs в основном реализуется как:

boomBangs xs = concatMap (\x -> (guard (odd x) >>= \_ -> [if x < 10 then "BOOM!" else "BANG!"])) xs
             = concatMap (\x -> concatMap (\_ -> [if x < 10 then "BOOM!" else "BANG!"]) guard (odd x)) xs

Так как для списка guard может быть специализирован для:

-- guard for the Monad []
guard :: Bool -> [()]
guard True = [()]
guard False = []

Таким образом, это означает, что если guard получает True, он возвращает одноэлементный список, а для False пустой список. Таким образом, это означает, что если охранник удерживает, concatMap (\_ -> [if x < 10 then "BOOM!" else "BANG!"]) вернет содержимое в [if x < 10 then "BOOM!" else "BANG!"], если охранник не сработает, он вернет пустой список. Таким образом, охрана действует как своего рода фильтр.

Итак, что же такое x <-. Если мы посмотрим, как do-выражения обесахариваются, x <- foo соответствует foo >>= \x -> ....

Для понимания списков x <- ... действует как своего рода «перечислитель»: он будет перечислять все элементы в списке, а x каждый раз будет получать один из элементов в списке для дальнейшей обработки.

person Willem Van Onsem    schedule 12.08.2019