Я пытаюсь понять, как интерпретации списка Haskell работают "под капотом" в отношении соответствия шаблонов. Следующий вывод ghci иллюстрирует мою точку зрения:
Prelude> let myList = [Just 1, Just 2, Nothing, Just 3]
Prelude> let xs = [x | Just x <- myList]
Prelude> xs
[1,2,3]
Prelude>
Как вы можете видеть, он может пропустить "Nothing" и выбрать только "Just". Я понимаю, что Список - это монада, определяемая как (источник из Real World Haskell, глава 14):
instance Monad [] where
return x = [x]
xs >>= f = concat (map f xs)
xs >> f = concat (map (\_ -> f) xs)
fail _ = []
Таким образом, понимание списка в основном создает одноэлементный список для каждого элемента, выбранного в понимании списка, и объединяет их. Если совпадение шаблона не выполняется на некотором шаге, вместо этого используется результат функции "fail". Другими словами, шаблон "Just x" не совпадает, поэтому [] используется в качестве заполнителя, пока не будет вызвано "concat". Это объясняет, почему "Nothing" кажется пропущенным.
То, что я не понимаю, как Хаскелл знает, чтобы вызвать функцию "fail"? Это "магия компилятора" или функциональность, которую вы можете написать в Haskell? Можно ли написать следующую функцию "select", чтобы работать так же, как понимание списка?
select :: (a -> b) -> [a] -> [b]
select (Just x -> x) myList -- how to prevent the lambda from raising an error?
[1,2,3]