Pergunta

Um dia eu estava entediado e queria exercitar meu cérebro, então decidi fazer o 99 problemas de Haskell mas me limitei a fazê-los sem problemas.Um problema que parece surgir muito quando estou fazendo coisas sem pontos é este:Como você aplica múltiplas funções ao mesmo valor enquanto mantém cada resultado como uma entidade independente?Usando notação pontiaguda:

foobar x = [id x, reverse x]

E o que descobri até agora em notação sem pontos:

foobar' = `map` [id, reverse] ($ x)

Eu não consigo entender isso x no final dali.

Foi útil?

Solução

Outros já postaram como você pode fazer isso usando o Reader mônada, mas essa não é a única maneira.Acontece que sua segunda função está bem próxima.Acho que você quis postar

foobar' x = (`map` [id, reverse]) ($ x)

Desde o x já está perto da posição mais à direita, você está quase lá.Primeiro, transforme a seção ($ x) em uma função, porque é um pouco mais fácil de trabalhar:

-- by the definition of a right operator section
foobar'2 x = (`map` [id, reverse]) (\y -> ($) y x)

Em seguida remova o x do corpo lambda trazendo uma nova variável para o escopo e aplicando a função a x

-- lambda abstraction I think...
foobar'2 x = (`map` [id, reverse]) $ (\z y -> ($) y z) x

Reescreva esta aplicação como uma composição de função e então você poderá reduzir eta:

-- by definition of '.'
foobar'3 x = (`map` [id, reverse]) . (\z y -> ($) y z) $ x

-- eta reduction
foobar'4 = (`map` [id, reverse]) . (\z y -> ($) y z)

Finalmente, observe que podemos substituir o lambda por uma função

-- by definition of `flip`
foobar'5 = (`map` [id,reverse]) . flip ($)

e você tem um formulário sem pontos.

Outras dicas

Você estará interessado no Applicative instância da mônada leitora:

instance Applicative (e ->)

Usando-o você pode distribuir facilmente um argumento:

liftA2 (+) sin cos 3

Aqui sin e cos são funções, e ambas recebem o valor 3.Os resultados individuais são então combinados usando (+).Você pode ainda combinar isso com o Category instancia de (->), mas é claro versões especializadas de (.) e id já estão definidos no Prelude.

Fundo:O Applicative exemplo para (e ->) realmente representa o cálculo SKI, onde (<*>) é o S combinador e pure é o K combinador. S é usado precisamente para distribuir um argumento para duas funções:

S f g x = f x (g x)

É necessário um aplicativo de função (f g) e torna ambos dependentes do valor x ((f x) (g x)).

Usar seqüência:

> let foobar' = sequence [id, reverse]
> foobar' "abcde"
["abcde","edcba"]

Existem alguns combinadores idiomáticos básicos que aparecem repetidamente e são reimplementados com vários conceitos e bibliotecas superiores, mas que são essencialmente muito simples.Os nomes podem variar e alguns são implementáveis ​​em termos de outros:

fork (f,g) x = (f x, g x)              -- == (f &&& g)
prod (f,g) x = (f $ fst x, g $ snd x)  -- == (f *** g)
pmap f (x,y) = (f x, f y)              -- == (f *** f)
dup     x    = (x,x)

etc.Claro uncurry f (x,y) == f x y se acostuma muito com isso também.

&&& e *** são definidos em Control.Arrow, assim como first e second.Então prod (f,id) == first f, prod(id,g) == second g etc.etc.

Então seu foobar torna-se

foobar = (\(a,b)->[a,b]) . fork (id,reverse)
       = (\(a,b)->[a,b]) . (id &&& reverse)
       = (\(a,b)->[a,b]) . (id *** reverse) . dup 
       = join $ curry ( (\(a,b)->[a,b]) . second reverse)

Para o último você também precisa importar Control.Monad e Control.Monad.Instances.Veja também essa questão.


edição tardia: também, usando Control.Applicative como sugerido na resposta de ertes,

       = (:) <*> ((:[]) . reverse)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top