2011-01-19 13 views
5

Estoy tratando de implementar un morfismo foreach para probar mi comprensión de la definición del morfismo y la coincidencia de patrones ... Obviamente omito ambos puntos por completo.implementación de principiante/aprendiz de foreach en haskell

¿Podría corregirme? Quiero que el morfismo foreach tome una lista de a y un morfismo f como argumentos y para devolver la lista de todos los resultados r de f aplicados a todos los elementos a.

foreach :: [a] → f → [r] 
foreach [] f = [] 
foreach x:[] f = (f x):[] 
foreach []:x f = []:(f x) 
foreach (x:xs) f = (f x) : (foreach (xs f)) 

Cuando compilado, he src\Main.hs:23:0: Parse error in pattern

+3

Por cierto: Esto ya existe, se llama 'map' y se define en la mitad de las líneas. – delnan

+0

@delnan: con argumentos de esta manera, esto se llama 'for' (y se define en términos de' map' probablemente). –

+0

@Alexandre: Ah sí, orden de argumento pasado por alto ... definición sería 'flip map'. – delnan

Respuesta

12

El problema es s yáctico, en esta línea:

foreach x:[] f = (f x):[] 

La aplicación del constructor en los patrones generalmente debe estar entre paréntesis. Esto funcionaría:

foreach (x:[]) f = (f x):[] 

Por cierto ... la aplicación de funciones es la más alta prioridad, por lo que por otra parte no es necesario paréntesis en el lado derecho:

foreach (x:[]) f = f x:[] 

Lo anterior es válido para cualquier constructor infija, pero como nota final, para las listas, en particular, hay una sintaxis especial:

foreach [x] f = [f x] 

hay otros problemas con su código tal como está, pero ese es el error inmediato. Una visión rápida de los otros problemas:

foreach :: [a] → f → [r] 

variables de tipo están implícitamente universalmente cuantificadas, por lo que esto significa cualquier tipo f. Necesita un tipo más específico, es decir, a -> r.

foreach x:[] f = (f x):[] 

Esto es innecesario - el caso recursivo funcionará correctamente aquí, aplicando f-x y se hace llamar en la cola, dando el caso lista vacía.

foreach []:x f = []:(f x) 

no creo que esto significa lo que creo que significa - esta es la coincidencia de patrones de la cabeza de una lista con la lista vacía [], lo que implica que la función está trabajando en una lista de listas.

foreach (x:xs) f = (f x) : (foreach (xs f)) 

Los paréntesis aquí son innecesarios o incorrectos. De nuevo, la aplicación de función tiene mayor prioridad que operadores como :. Además, (xs f) significa aplicar xs a f, como si fuera una función.Para aplicar foreach a dos argumentos, bastará con foreach xs f.


Para la comparación, aquí está el código fuente de la (idénticos excepto por orden de los argumentos) la función de la biblioteca estándar map:

map :: (a -> b) -> [a] -> [b] 
map _ []  = [] 
map f (x:xs) = f x : map f xs 
+0

thx para todas las precisiones, a saber, la aplicación de función con mayor precedencia. –

+0

y gran ejemplo con la implementación del mapa –

2

te han olvidado poner en ()foreach []:x f = []:(f x) e incorrectamente se especifica el tipo de función, el siguiente debe ahora recopilar:

foreach :: [a] -> (a -> r) -> [r] 
foreach [] f = [] 
foreach (x:[]) f = (f x):[] 
foreach (x:xs) f = (f x) : (foreach xs f) 

y ejecute:

*Main> foreach [1..20] (+1) 
[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21] 
+0

'(a -> r)' aquí significa que el segundo argumento para 'foreach' es la función que convierte el tipo' a' en tipo 'r'. Si, por ejemplo, especificaras el tipo de función como 'foreach :: [a] -> (a -> a) -> [a]', no podrías evaluar 'foreach [1..20] show', porque 'show' produce un' String', y su función toma valor de un tipo y devuelve el valor del mismo tipo. –

+0

agradecimiento Yasir ;-) –

+0

: -o Eres Preguntas @Stephane bienvenida con etiqueta "Haskell" son mucho más activos que "esquema", "raqueta" o "Erlang" son. Creo que necesito pasar un rato aquí. –

3

La firma de tipo que se da, es (al menos en opinión del compilador de Haskell) falso. Es una función que toma una lista de elementos de cualquier a y un valor de cualquier tipo f, y produce una lista de valores de cualquier tipo r. Es como decir "Tengo un montón de elefantes y un destornillador. Convierta cada elefante en un mango".

Parece que su objetivo es implementar la función map:

map :: (a -> b) -> [a] -> [b] 

Por supuesto, es perfectamente válido para voltear los argumentos:

foreach :: [a] -> (a -> b) -> [b] 

Su aplicación es bastante estrecha, pero hay una algunos problemas

Lo más importante es tener en cuenta que se trabaja con listas , no matrices. El operador :, también conocido como "contras", toma un elemento y lo incluye en una lista (por ejemplo, 1 : [2,3,4]). No puede usarlo para concatenar elementos y listas arbitrariamente, como lo hace en []:(f x). Existe el operador ++ que concatena dos listas (por ejemplo, [f x] ++ xs, que es lo mismo que (f x) : xs), pero no debería necesitar implementar foreach.

Por último, (foreach (xs f)) no hace lo que usted piensa que hace. No es como foreach(xs,f) en un lenguaje de estilo C, es como foreach(xs(f)). (xs f), por sí mismo, es como usar xs como una función y aplicar f como argumento. En cambio, quiere (foreach xs f).

voy a parar aquí, para evitar revelar demasiado. Sin embargo, un pequeño tidbit: la aplicación de función tiene mayor precedencia que cualquier operador, por lo que en lugar de (f x) : (foreach xs f), puede decir f x : foreach xs f.

+0

, es bueno saber que ya existe como mapa. Lo he usado en el tutorial, pero lo olvidé ;-), lo usaré ahora. También he notado la existencia de la palabra clave for all como una propuesta de autocompletado de Leksah, pero no pude encontrar su sintaxis. –

+0

@Stephane Rolland: 'forall a b. (a -> b) -> [a] -> [b] '. Tendrá que habilitar una extensión de idioma Haskell para usar esta sintaxis. Ver [Tipos cuantificados existencialmente] (http://en.wikibooks.org/wiki/Haskell/Existentially_quantified_types). –

Cuestiones relacionadas