¿Hay alguna manera conveniente de usar un patrón como función de predicado?

10

Recientemente me he encontrado con situaciones en las que necesito pasar una función de predicado a otra función, y con frecuencia la lógica que estoy buscando es esencialmente "¿este valor coincide con este patrón?"

La coincidencia de patrones parece preferirse en declaraciones, dobloques y comprensiones de listas, pero hay una serie de funciones que toman un predicado a -> Bool, donde sería muy útil pasar de alguna manera un patrón. Por ejemplo, takeWhile, until, find, span, etc.

Hasta ahora he estado haciendo \a -> case a of MyCons _ -> True; otherwise -> False, o escribiendo una función con nombre a la let myPred (MyCons _) = True; myPred _ = False inpero ambos parecen terriblemente feos y no muy idiomáticos. La forma "obvia" (e incorrecta) sería algo así, \(MyCons _) -> Truepero arroja un error por ser parcial, naturalmente, e incluso entonces parece que debe haber una forma más limpia.

¿Hay una manera más sucinta / limpia de hacer este tipo de cosas? ¿O estoy yendo por cosas completamente equivocadas?

David Sampson
fuente
1
Tal vez esto sea una cuestión de "gusto personal", pero si solo necesita este predicado en un lugar, estaría muy contento con la letcláusula que no le gusta, aunque prefiero la wherecláusula equivalente para que esto no sature la definición principal. Por supuesto, si termina necesitando esta utilidad más de una vez, la definiría como una función de nivel superior.
Robin Zigmond
Ciertamente funciona bien. Mi pregunta estaba algo motivada por lo impresionantemente sucinta que suele ser Haskell. Por lo general, parece que Haskell idiomático tiene muy poca duplicación de ideas y mantiene la pelusa al mínimo. Por lo tanto, ni siquiera es necesariamente que piense que el let myPred...estilo es malo , pero se siente mucho más detallado de lo que esperaría para una idea muy simple, lo que me lleva a preguntarme si estoy ladrando el árbol equivocado.
David Sampson
2
Puede echar un vistazo a los prismas (de la lente). Son como patrones
compostables de
1
Creo que deberíamos ver un ejemplo de dónde está utilizando este tipo de función de orden superior. Parte de mí quiere decir que el problema es con el diseño que requiere dicho predicado en primer lugar.
chepner
la forma de Haskell98, para esto, es definir la función de coincidencia de mayúsculas y minúsculas (deconstrucción) para su tipo de datos, como maybe :: b -> (a -> b) -> Maybe a -> by bool :: a -> a -> Bool -> a, luego, usarla con funciones productoras de Boole como argumento (s). por ejemplo myCons z f (MyCons x) = f x ; myCons z f _ = z, luego llame myCons False (const True) aMyConsValue. esto es casi lo que escribió, solo tiene un nivel más de "indirección" / "abstracción" a través de argumentos funcionales, integrado en él.
Will Ness

Respuestas:

7

Puede usar la extensión de idioma LambdaCase para usar \case MyCons _ -> True; _ -> False, aunque esto no guarda tantos caracteres.

Creo que podría escribir una serie de funciones constructedWith :: (Generic a) => (b -> a) -> a -> Bool, constructedWith2 :: (Generic a) => (b -> c -> a) -> a -> Boolpero no soy lo suficientemente competente con Generics para implementarlo sin unas pocas horas de prueba. Intentaré esto y editaré mi respuesta si puedo resolverlo o si es un callejón sin salida.

EDITAR: Sí, puedes hacerlo! Aquí hay un enlace a mi código, que lo implementa todo desde cero:

https://repl.it/@lalaithion/ConstructedWith

Sin embargo, usar algo como http://hackage.haskell.org/package/generic-deriving-1.13.1/docs/Generics-Deriving-ConNames.html para todas las tuberías genéricas de código podría ser mejor.

Izaak Weiss
fuente