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

StackOverflow https://stackoverflow.com/questions/907306

  •  05-09-2019
  •  | 
  •  

Вопрос

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

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.

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

Это было полезно?

Решение

Определение $

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top