2012-01-24 12 views
9

Estoy tratando de integrar numéricamente una función en Haskell usando la regla trapezoidal, devolviendo una anti-derivada que toma los argumentos a, b, para que se integren los puntos finales del intervalo.Haskell: where cláusula referenciando variables enlazadas en lambda

integrate :: (Float -> Float) -> (Float -> Float -> Float) 

integrate f 
    = \ a b -> d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
    where 
     d = (b - a)/n 
     n = 1000 

En lo anterior, utilizo

n - for the number of subintervals 
d - for the width of each subinterval 

Esto casi funciona, a excepción de los argumentos ligados a, b en el lambda. Consigo el mensaje de error :

Not in scope: `b' 
Not in scope: `a' 

me puede entender que el alcance de a, b se limita sólo a eso expresión lambda, pero Hay una solución alternativa en Haskell para que yo no tengo que escribir (ba)/n para cada ocurrencia de d en lo anterior?

+4

TIL: No se puede usar 'WHERE' con lambdas [dejar vs donde] (http://www.haskell.org/haskellwiki/Let_vs._Where). Ver también [dónde hace la cláusula 'where' ser útil en Haskell] (http://stackoverflow.com/questions/6032183/where-does-the-where-clause-come-in-handy-in-haskell) – rampion

+0

Gracias a todos los que respondieron. No me di cuenta de que este problema conduce directamente a un debate conocido entre nosotros. También quiero agradecer a aquellos que me sugirieron que escribiera la función como: integrar f a b = ... Esa es una solución agradable y sucinta también. – Bylextor

Respuesta

1

intento:

integrate f a b = d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
    where 
     d = (b - a)/n 
     n = 1000 
16

que estás pensando necesita devolver una función que toma dos Float s y devuelve un Float, pero en realidad eso no es diferente a la toma de dos Float argumentos adicionales en su función integrate y el uso currying (es decir, simplemente no los proporcione y el tipo de devolución será Float -> Float -> Float).

Para que pueda reescribir su función como esta

integrate :: (Float -> Float) -> Float -> Float -> Float 

integrate f a b 
    = d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
    where 
     d = (b - a)/n 
     n = 1000 

o puede utilizar en lugar de let ... inwhere:

integrate f 
    = \a b -> 
     let d = (b - a/n) 
      n = 1000 
     in d * sum [ f (a + d * k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
+2

FWIW, Matthew omitió los paréntesis en la firma de tipo, pero eso no es necesario. Puede mantener la firma del tipo igual y escribir el cuerpo de la función de esta nueva manera. Las dos firmas son * exactamente * equivalentes. – luqui

+0

Bien manchado. Tenía la intención de mencionarlo cuando estaba escribiendo la respuesta, pero debo haberlo olvidado. –

+0

Gracias. Reescribir la función como integrar f a b = ... es una gran solución. – Bylextor

4

Claro.

integrate f a b = d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
    where 
     d = (b - a)/n 
     n = 1000 
2

Si insiste en donde:

integrate f = \a b -> case() of 
    () -> d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
      where 
       d = (b - a)/n 
       n = 1000 

se ve bastante bien, ¿no es así? Para hacer que el caso parece un poco más motivados:

integrate f = \a b -> case (f a + f b) of 
    fs -> d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * fs 
      where 
       d = (b - a)/n 
       n = 1000 
+0

¡Muy listo! ¡Gracias! – Bylextor

3

Usted tiene una gran cantidad de soluciones temporales.

Si usted no sabe cualquier sintaxis de enlace, excepto las expresiones lambda se puede hacer esto (que me encanta la mayoría debido a su belleza teórico, pero nunca usar debido a su fealdad sintáctica):

integrate f 
    = \a b -> (\d -> d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b)) 
      ((b - a)/n) 
    where 
     n = 1000 

Si te gusta definiciones y sólo sabe where -Sintaxis usted puede hacer esto:

integrate f = go 
    where 
    n = 1000 
    go a b = d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
     where 
     d = (b - a)/n 

Si también sabe let -Sintaxis, usted puede hacer esto:

integrate f = 
    \a b -> let d = (b - a)/n 
      in d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
    where 
    n = 1000 

Por último, si se recuerda que a -> (b -> c -> d) es lo mismo que a -> b -> c -> d, se puede hacer lo obvio:

integrate f a b = d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
    where 
    n = 1000 
    d = (b - a)/n 
+1

Hay otra razón para no usar la primera opción: las lambdas no tienen polimorfismo. – luqui

+0

Gracias. La opción let es probablemente la solución más simple para mi problema where bound-variable. – Bylextor

+0

¿Me puede decir algo más sobre "ir"? Intenté buscarlo, pero es muy difícil encontrar información sobre "ir" en Haskell, porque los motores de búsqueda lo confunden con la palabra usual en inglés "ir", y "ir" no aparece en la mayoría de los índices de libros. – Bylextor