Pregunta

De vez en cuando me tropiezo con el problema que quiero expresar "por favor utilice el último argumento dos veces", por ejemplo, con el fin de escribir estilo pointfree o para evitar una lambda. Por ejemplo.

sqr x = x * x

podría escribir como

sqr = doubleArgs (*) where
   doubleArgs f x = f x x

O considere esta función un poco más complicado (tomado de esta pregunta ):

ins x xs = zipWith (\ a b -> a ++ (x:b)) (inits xs) (tails xs)

Podría escribir el código pointfree si había una función como esta:

ins x = dup (zipWith (\ a b -> a ++ (x:b))) inits tails where
     dup f f1 f2 x = f (f1 x) (f2 x)

Pero como no puedo encontrar algo como doubleArgs o dup en Hoogle, así que supongo que puede ser que se pierda un truco o idioma aquí.

¿Fue útil?

Solución

De Control.Monad:

join :: (Monad m) -> m (m a) -> m a
join m = m >>= id

instance Monad ((->) r) where
    return = const
    m >>= f = \x -> f (m x) x

Ampliación:

join :: (a -> a -> b) -> (a -> b)
join f = f >>= id
       = \x -> id (f x) x
       = \x -> f x x

Así que, sí, Control.Monad.join.

Ah, y por su ejemplo pointfree, ¿Ha intentado utilizar la notación aplicativo (de Control.Applicative):

ins x = zipWith (\a b -> a ++ (x:b)) <$> inits <*> tails

(también no sé por qué la gente es tan aficionado a a ++ (x:b) en lugar de a ++ [x] ++ b ... no es más rápido - el revestimiento interior se hará cargo de él - y este último es mucho más simétrica Oh bien!)

Otros consejos

Lo que llamas '' doubleArgs se llama con más frecuencia DUP - es el combinador W (llamada curruca en burlarse de un ruiseñor) - "el duplicador primaria".

Lo que llamas 'dup' es en realidad el combinador 'Starling-prime'.

Haskell tiene una bastante pequeña "base combinador" ver Data.Function, además de algunas operaciones de aplicativos y Monádicos añadir más combinadores "estándar" en virtud de las instancias de función para Aplicativo y Mónada (<*> del Aplicativo es el S - Starling combinador para la instancia funcional, liftA2 y liftM2 se Starling-prime). No parece ser mucho entusiasmo en la comunidad para expandir Data.Function, así que mientras combinadores son muy entretenidos, pragmáticamente he llegado a preferir siempre a mano en situaciones en las que un combinador no está disponible directamente.

Aquí hay otra solución para la segunda parte de mi pregunta: Flechas

import Control.Arrow

ins x = inits &&& tails >>> second (map (x:)) >>> uncurry (zipWith (++))

El &&& ( "fanout") distribuye un argumento a dos funciones y devuelve el par de los resultados. >>> ( "y luego") invierte el orden de aplicación de función, lo que permite tener una cadena de operaciones de izquierda a derecha. second sólo funciona en la segunda parte de un par. Por supuesto que necesita un uncurry al final de alimentar a la pareja en una función que espera dos argumentos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top