2012-01-19 22 views
17

A menudo tienen una función de tal patrón:Haskell - coincidencia de patrones azúcar sintáctico y donde

f :: a -> b 
f x = case x of 
    ... -> g ... 
    ... -> g ... 
    ... 
    ... -> g ... 
    where g = ... 

No es un azúcar sintáctica para casi este caso:

f :: a -> b 
f ... = g ... 
f ... = g ... 
... 
f ... = g ... 

Desafortunadamente lo que pueda' Adjunte mi where a él: Obviamente obtendré un montón de not in scope s. Puedo hacer que g sea una función separada, pero no es agradable: el espacio de nombres de mi módulo estará contaminado con funciones de utilidad. ¿Hay alguna solución?

+4

Usted no tiene que exportar 'G ', así la contaminación del espacio de nombres es sólo un problema * * dentro de su propio módulo. –

Respuesta

10

Creo que su primer ejemplo no está nada mal. El único peso sintáctico es case x of, más -> en lugar de =; esto último se compensa con el hecho de que puede omitir el nombre de la función para cada cláusula. De hecho, incluso la función auxiliar propuesta por dflemstr go es sintácticamente más pesada.

Es cierto que es ligeramente inconsistente en comparación con la sintaxis de la cláusula de función normal, pero esto es probablemente una buena cosa: delimita visualmente de forma más precisa el alcance en el que x está disponible.

+0

La sintaxis ecuacional para definir funciones parece una especie de artilugio innecesario. –

10

No, no hay solución. Cuando tiene varias cláusulas para una función como esa, no pueden compartir una cláusula where. Su única opción es utilizar una declaración de caso, o hacer algo como esto:

f x = 
    go x 
    where 
    go ... = g ... 
    go ... = g ... 
    g = ... 

... si realmente desea utilizar una forma de función por alguna razón.

6
f = g . h -- h is most of your original f 
    where h ... = ... 
     h ... = ... 
     g = 
+0

Creo que el OP estaba buscando una solución general al problema donde 'g' podría aparecer en cualquier parte del RHS de cualquiera de las ecuaciones (o no aparecer en absoluto). –

+1

Sí, sentí que la pregunta era ambigua y le di una respuesta para el caso que aún no había sido respondida. – dave4420

3

La solución original parece ser la mejor y única solución. Desde el punto de vista sintáctico, no es más pesado que la coincidencia directa de patrones en los parámetros de la función, sino incluso más clara.

Pero por si acaso, si lo que necesita es solo verificar las condiciones previas y no coincidencia de patrones, no se olvide de las protecciones, que le permiten acceder al alcance where libremente. Pero realmente no veo nada malo en su solución case of.

f :: a -> b 
f a 
    | a == 2 = ... 
    | isThree a = ... 
    | a >= 4 = ... 
    | otherwise = ... 
    where isThree x = x == 3 
5

De Haskell en 2010, o con GHC también se puede hacer:

f x 
    | m1 <- x = g 
    | m2 <- x = g 
    ... 
    where g = 

pero tenga en cuenta que no puede utilizar las variables ligadas en los patrones de g. Es equivalente a:

f x = let g = ... in case() of 
    () -> case x of 
      m1 -> g 
      _ -> case x of 
       m2 -> g 
       .... 
1

¿Es seguro asumir que utiliza constantemente g en la mayoría, si no todas, de las diferentes ramas de la declaración de caso?

Funcionamiento con la suposición de que f :: a -> b para algunos a y b (posiblemente polimórfica), g es necesariamente una función de la forma c -> d, lo que significa que hay debe ser una manera de extraer consistentemente un c de un a. Llame al getC :: a -> c.En ese caso, la solución sería simplemente usar h . g . getC para todos los casos, donde h :: d -> b.

Pero supongamos que no siempre se puede obtener la c cabo de un a. ¿Quizás a tiene la forma f c, donde f es Functor? Entonces podría fmap g :: f c -> f d, y luego de alguna manera transformar f d en un b.

Solo un poco de divagaciones aquí, pero fmap fue lo primero que se me ocurrió cuando vi que parecía estar aplicando g en cada rama.

0

Con LambdaCase, también se puede hacer esto:

{-# language LambdaCase #-} 

f :: a -> b 
f = \case 
    ... -> g ... 
    ... -> g ... 
    ... 
    ... -> g ... 
    where g = ... 
Cuestiones relacionadas