simbolos programa opciones mundo multiplicar imprimir hola hacer como basico haskell type-conversion type-families

programa - Tipo de conversión automática en haskell



programa en haskell (2)

Esta respuesta probablemente no sea útil para usted, ya que con toda probabilidad ya ha considerado la alternativa que voy a sugerir y la consideró insuficiente para sus propósitos diabólicos. Aún así, los lectores que tropiezan con esta pregunta pueden encontrar útil saber cómo lograr algo similar a lo que estabas buscando, si no tan ingenioso, sin trucos de tipo de clase.

En tus planes, un BoolLike a ...

newtype BoolLike a = BoolLike ((a -> Bool) -> Bool)

... consiste en una función que produce un resultado Bool cuando se le da una a -> Bool continuación de a -> Bool . Sus ejemplos de uso se reducen a la combinación de los resultados de Bool con (&&) y (||) antes de suministrar la continuación. Esto se puede lograr usando la instancia Applicative para funciones (en este caso, (->) (a -> Bool) ) y usando (&) / flip ($) para promover valores simples en (a -> Bool) -> Bool "cálculos suspendidos":

GHCi> ((||) <$> ((&&) <$> ($ 1) <*> ($ 2)) <*> ($ 3)) (`elem` [2]) False

Eso, por supuesto, no es del todo ordenado para escribir. Sin embargo, podemos mejorar mucho las cosas definiendo:

(<&&>) :: Applicative f => f Bool -> f Bool -> f Bool x <&&> y = (&&) <$> x <*> y (<||>) :: Applicative f => f Bool -> f Bool -> f Bool x <||> y = (||) <$> x <*> y

(Para una pequeña biblioteca que los define, eche un vistazo a control-bool ).

Armado con estos, el ruido de línea adicional se vuelve bastante ligero:

GHCi> (($ 1) <&&> ($ 2) <||> ($ 3)) (`elem` [2]) False

Esto también funciona de forma predeterminada para el caso de contains ; todo lo que se necesita es cambiar la continuación suministrada:

GHCi> (($ [1, 2]) <&&> ($ [2, 3]) <||> ($ [3, 4])) (elem 1) False

Como nota final, vale la pena señalar que el caso contains puede expresarse directamente en términos de intersect y union de Data.List :

GHCi> [1, 2] `intersect` [2, 3] `union` [3, 4] & elem 1 False

He escrito algunas funciones útiles para hacer una operación lógica. Parece que (a and b or c) `belongs` x .

Gracias a Num , IsList y OverloadedLists , puedo tenerlo para enteros y listas.

λ> (1 && 2 || 3) `belongs` [2] False λ> (1 && 2 || 3) `belongs` [1, 2] True λ> (1 && 2 || 3) `belongs` [3] True λ> :set -XOverloadedLists λ> ([1, 2] && [2, 3] || [3, 4]) `contains` 1 False λ> ([1, 2] && [2, 3] || [3, 4]) `contains` 2 True

Lo hago de esta manera:

newtype BoolLike a = BoolLike ((a -> Bool) -> Bool) (&&) :: BoolLike a -> BoolLike a -> BoolLike a BoolLike f && BoolLike g = BoolLike $ /k -> f k P.&& g k infixr 3 && toBoolLike :: a -> BoolLike a toBoolLike x = BoolLike $ /k -> k x belongs :: Eq a => BoolLike a -> [a] -> Bool belongs (BoolLike f) xs = f (/x -> x `elem` xs) contains :: Eq a => BoolLike [a] -> a -> Bool contains (BoolLike f) x = f (/xs -> x `elem` xs) instance Num a => Num (BoolLike a) where fromInteger = toBoolLike . fromInteger

Lo que voy a hacer es adaptarlo a cualquier tipo, sin convertirlo manualmente a BoolLike a .

¿Cómo puedo lograrlo?

Primer intento:

class IsBool a where type BoolItem a toBool :: a -> BoolItem a instance IsBool (BoolLike a) where type BoolItem (BoolLike a) = BoolLike a toBool = id instance IsBool a where type BoolItem a = BoolLike a toBool = toBoolLike

Ha fallado:

Conflicting family instance declarations: BoolItem (BoolLike a) -- Defined at BoolLike.hs:54:8 BoolItem a -- Defined at BoolLike.hs:58:8


Podrías probar esto

type family BoolItem a where BoolItem (BoolLike a) = BoolLike a BoolItem a = BoolLike a class IsBool a where toBool :: a -> BoolItem a instance IsBool (BoolLike a) where toBool = id instance (BoolItem a ~ BoolLike a) => IsBool a where toBool = toBoolLike

Al mover la familia tipográfica de la clase, puede definirla para todos los tipos. Entonces todo lo que queda es restringir una de las instancias. No olvides que también necesitarás hacer que sea OVERLAPPABLE