Подтвердить что ты не робот

Почему моя Haskell делает нотацию, когда я пытаюсь ее отрезать?

У меня есть следующий код из Проблема 26 проблем 99 Haskell:

combinations :: Int -> [a] -> [[a]]
combinations 0 _  = return []
combinations n xs = do y:xs' <- tails xs
                       ys <- combinations (n-1) xs'
                       return (y:ys)

Вышеприведенный код работает так, как ожидалось. Ниже приведена моя основная функция и напечатанные результаты:

main = print $ combinations 2 "abcd"
-- Prints: ["ab","ac","ad","bc","bd","cd"]

В качестве учебного упражнения я попытался "desugar" сделать нотацию следующим образом:

combinations :: Int -> [a] -> [[a]]
combinations 0 _  = return []
combinations n xs = tails xs >>= \(y:xs') ->
                    do
                        ys <- combinations (n-1) xs'
                        return (y:ys)

Этот компилятор, но дает следующую ошибку во время выполнения:

PatternMatchFail: /home/.../test.hs:(46,34)-(49,37): Non-exhaustive patterns in lambda

Что здесь происходит? Как заменить примечание do на >>= и >>?

4b9b3361

Ответ 1

Из Haskell Wikibook:

... фрагмент с лямбдами был "широко эквивалентен" блоку do. Это не точный перевод, потому что в примечании добавляется специальная обработка ошибок совпадения шаблонов.

Рассмотрим следующий пример:

f xs = do
       (x:_) <- Just xs
       return x  

g xs = Just xs >>=
       \(x:_) -> return x

Для любого непустого списка эти функции идентичны. Но f [] возвращает Nothing, а g [] возвращает ошибку, подобную той, которую вы получаете.

Это связано с тем, что нотация do обрабатывает ошибку по-разному. Класс Monad имеет функцию fail. Вы используете монаду списка, которая терпит неудачу, возвращая пустой список. Монада Maybe реализует его, возвращая Nothing. В любом случае, ошибка совпадения шаблонов внутри нотации do обрабатывается с помощью этой функции, следовательно, разница.

Таким образом, правильный способ его перевода:

g xs = Just xs >>= 
       \xs' -> case xs' of
                 (x:_) -> return x
                 []    -> fail "some error"