Путаница в отношении каррирования и стиля без точек в Haskell

Я пытался реализовать функцию

every :: (a -> IO Bool) -> [a] -> IO Bool 

который был темой для этого вопрос. Я попытался сделать это без явной рекурсии. Я придумал следующий код

every f xs = liftM (all id) $ sequence $ map f xs

Моя функция не сработала, так как она не была ленивой (что и требовалось в вопросе), поэтому никаких голосов там не было :-).

Однако на этом я не остановился. Я постарался сделать функцию безточечной, чтобы она была короче (а может, даже круче). Поскольку аргументы f и xs являются последними в выражении, я только что их отбросил:

every = liftM (all id) $ sequence $ map 

Но это не сработало, как ожидалось, на самом деле это не сработало совсем:

    [1 of 1] Compiling Main             ( stk.hs, interpreted )

    stk.hs:53:42:
        Couldn't match expected type `[m a]'
               against inferred type `(a1 -> b) -> [a1] -> [b]'
        In the second argument of `($)', namely `map'
        In the second argument of `($)', namely `sequence $ map'
        In the expression: liftM (all id) $ sequence $ map
    Failed, modules loaded: none.

Это почему? У меня создалось впечатление, что можно просто отбросить конечные аргументы функции, что в основном и есть в каррировании.


person Jonas    schedule 25.05.2009    source источник


Ответы (1)


Определение $ - это

f $ x = f x

Давайте полностью заключим вашу функцию в скобки:

every f xs = (liftM (all id)) (sequence ((map f) xs))

и ваша карри-версия:

every = (liftM (all id)) (sequence map)

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

f x = g c x

на самом деле

f x = (g c) x

и приложение (g c) к x идет последним, поэтому вы можете написать

f = g c

Один из паттернов с оператором приложения $ состоит в том, что он часто становится оператором композиции. в безбалльных версиях. Это потому что

f $ g $ x

эквивалентно

(f . g) $ x

Например,

every f xs = liftM (all id) $ sequence $ map f xs

может стать

every f xs = (liftM (all id) . sequence . map f) xs

в этот момент вы можете сбросить xs:

every f = liftM (all id) . sequence . map f

Исключить аргумент f сложнее, потому что он применяется перед оператором композиции. Давайте воспользуемся определением точки из http://www.haskell.org/haskellwiki/Pointfree:

dot = ((.) . (.))

С очками это

(f `dot` g) x = f . g x

и это именно то, что нам нужно, чтобы полностью избавить от очков:

every = (liftM (all id) . sequence) `dot` map

К сожалению, из-за ограничений в системе типов Haskell для этого требуется явная сигнатура типа:

every :: (Monad m) => (a -> m Bool) -> [a] -> m Bool
person Dave    schedule 25.05.2009
comment
Или вы можете использовать -XNoMonomorphismRestriction и удалить явный тип sig. - person GS - Apologise to Monica; 25.05.2009
comment
Ох ... определение dot выглядит так, будто кто-то смотрит на меня. - person gawi; 09.10.2010