2012-07-29 30 views
25

Estaba aburrido un día y quería ejercitar mi cerebro, así que decidí hacer el 99 Haskell Problems pero me limité a hacerlo en estilo sin puntos. Un problema que parece surgir mucho cuando estoy haciendo cosas en un estilo sin puntos es este: ¿cómo se aplican múltiples funciones al mismo valor mientras se mantiene cada resultado como una entidad independiente? Utilizando la notación de punta:Aplicar varias funciones al mismo valor sin puntos en Haskell

foobar x = [id x, reverse x] 

Y lo que he encontrado hasta el momento en notación sin punto:

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

Me parece que no puede conseguir que la x fuera de la final de allí.

Respuesta

25

Otros ya han publicado cómo se puede hacer esto utilizando la mónada Reader, pero esa no es la única manera. Resulta que tu segunda función es bastante cercana. Creo que quería decir para publicar

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

Desde el x ya está cerca de una posición más a la derecha, que está casi allí.En primer lugar, transformar la sección ($ x) en una función, ya que es un poco más fácil trabajar con:

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

A continuación retire la x del cuerpo lambda trayendo una nueva variable en el alcance y la aplicación de la función de x

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

Reescribe esta aplicación como una composición de funciones, y entonces usted puede reducir 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 reemplazar el lambda con una función

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

y tiene un formulario libre de puntos.

8

Usted estará interesado en el Applicative instancia del lector mónada:

instance Applicative (e ->) 

Su uso se puede distribuir fácilmente un argumento:

liftA2 (+) sin cos 3 

Aquí sin y cos son funciones, que ambos reciben el valor 3. Los resultados individuales se combinan usando (+). Puede combinar esto con la instancia Category de (->), pero las versiones especializadas de cource de (.) y id ya están definidas en el Prelude.

Antecedentes: La instancia Applicative para (e ->) realmente representa el cálculo SKI, donde (<*>) es el combinador S y pure es el combinador K. S se utiliza precisamente para distribuir un argumento para dos funciones:

S f g x = f x (g x) 

Se necesita una aplicación de función (fg) y hace que tanto depende del valor x ((fx) (gx))

9

Uso sequence:

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

Sólo si estás bien con las restricciones. Esto no funcionará para todos los usos. –

+0

@ ThomasM.DuBuisson: ¿qué restricciones? –

+0

@BenMillwood Me refiero a las restricciones de clase de clase. La respuesta de JohnL es de tipo 'a -> [a]'. Esta respuesta, aunque agradable y limpia, es de tipo 'Monad ((-> a) => a -> [a]'. –

5

Hay unos pocos combinadores idiomáticos básicos que aparecen repetidamente, y se vuelven a implementar con varios conceptos superiores y bibliotecas, pero que son esencialmente muy simples. Los nombres pueden variar, y algunos son implementables en cuanto a los demás:

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. Por supuesto uncurry f (x,y) == f x y se acostumbra mucho con ellos, también.

&&& y *** se definen en Control.Arrow, así como first y second. Entonces prod (f,id) == first f, prod(id,g) == second g etc etc

Así que su foobar convierte

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 el último que necesita también importar Control.Monad y Control.Monad.Instances. Vea también this question.


fines de edición: también, usando Control.Applicative como dio a entender en respuesta por ertes,

 = (:) <*> ((:[]) . reverse) 
+0

también,' (:) <*> (pure reverse) '(the' ((->) r), [ ] 'Applicatives),' ([id, reverse] <*>). Pure' (el '[]' Aplicativo), 'secuencia [id, reverso]' (el '((->) r)' Monad). –

Cuestiones relacionadas