Pergunta

Eu estava tentando implementar a função

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

que foi o tema para esta questão . Tentei fazer isso sem recursão explícita . Eu vim com o seguinte código

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

A minha função não funcionou uma vez que não era preguiçoso (que foi requerido na questão), por isso não upvotes lá: -).

No entanto, eu não param por aí. Eu tentei fazer a função sem ponto para que ele seria mais curto (e talvez até mais frio). Desde o f argumentos e xs são os últimos na expressão Eu só caiu-lhes:

every = liftM (all id) $ sequence $ map 

Mas isso não funcionou como esperado, na verdade, não fez a todos os:

    [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.

Por que isso? Fiquei com a impressão de que era possível deixar cair simplesmente arrastando os argumentos da função, que basicamente é o que currying é sobre.

Foi útil?

Solução

A definição de $ é

f $ x = f x

Vamos entre parênteses plenamente a sua função:

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

e sua versão curry:

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

Como você percebeu, estes não são idênticos. Você só pode soltar arrastando argumentos da função quando eles são a última coisa aplicada. Por exemplo,

f x = g c x

é realmente

f x = (g c) x

e a aplicação de (g c) x vem por último, assim você pode escrever

f = g c

Um padrão com o operador de inscrição R $ é que muitas vezes torna-se o operador de composição. em versões pontos livres. Isso ocorre porque

f $ g $ x

é equivalente a

(f . g) $ x

Por exemplo,

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

pode se tornar

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

em que ponto você pode cair xs:

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

Eliminar o argumento f é mais difícil, porque ele é aplicado antes que o operador composição. Vamos usar a definição do ponto de http://www.haskell.org/haskellwiki/Pointfree :

dot = ((.) . (.))

Com pontos, este é

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

e é exatamente o que precisamos para tornar cada totalmente pontos-livres:

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

Infelizmente, devido a restrições no sistema do tipo Haskell, este precisa de uma assinatura de tipo explícito:

every :: (Monad m) => (a -> m Bool) -> [a] -> m Bool
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top