2009-05-25 13 views
9

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

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

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

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

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

Однако я не останавливался на достигнутом. Я попытался сделать функцию точечной так, чтобы она была короче (и, возможно, даже более прохладной). Так как аргументы 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. 

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

ответ

25

Определение $ является

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 

и применение (дс) х приходит последним, так что вы можете написать

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 

в какой момент вы можете оставить хз:

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 
+2

Или вы можете использовать -XNoMonomorphismRestriction и отказаться от явного типа sig. –

+1

Argh ... определение 'dot' выглядит так, как будто кто-то смотрит на меня. – gawi

 Смежные вопросы

  • Нет связанных вопросов^_^