usar una que metodos metodo estaticos ejemplos cuando clases clase atributos haskell

haskell - una - que es un metodo en java



¿Es posible hacer que un tipo sea una instancia de una clase si sus parámetros de tipo están en el orden incorrecto? (4)

Esto no es posible, y no creo que sea pronto.

El orden de los parámetros de tipo es importante. El último valor es el que va a "contener" para usar con Functor, etc.

Traté de hacer que esto funcionara definiendo un sinónimo de tipo que cambiaba los parámetros de tipo y luego usaba la extensión TypeSynonymInstances , pero no funcionó.

Considere el siguiente tipo:

data SomeType m a = SomeType (m Integer) [a]

Podemos hacer que ese tipo sea una instancia de Functor con el siguiente código:

instance Functor (SomeType m) where fmap f (SomeType m lst) = SomeType m (map f lst)

Sin embargo, si en cambio, los parámetros del tipo SomeType fueron intercambiados:

data SomeType2 a m = SomeType2 (m Integer) [a]

Entonces la definición de instancia anterior no funciona.

¿Hay alguna forma de hacer que SomeType2 una instancia de Functor? Si no es así, ¿hay algunas adiciones prometedoras a haskell / ghc que lo hagan posible?


Estoy predispuesto, pero creo que esta es una gran oportunidad para hacer uso de Control.Newtype , una pequeña pieza de un kit que no es más que un "nuevo tipo de instalación de la camarilla".

Aquí está el trato. Desea voltear alrededor de los constructores de tipos para tener en sus manos la funcionalidad (por ejemplo) en un parámetro diferente. Definir un newtype

newtype Flip f x y = Flip (f y x)

y agregarlo a la clase Newtype así

instance Newtype (Flip f x y) (f y x) where pack = Flip unpack (Flip z) = z

La clase Newtype es solo un directorio que asigna newtypes a sus equivalentes sin barnizar, y proporciona un kit práctico, por ejemplo, la op Flip es la inversa de Flip : no es necesario recordar cómo se llama.

Para el problema en cuestión, ahora podemos hacer cosas como esta:

data Bif x y = BNil | BCons x y (Bif x y) deriving Show

Es un tipo de datos de dos parámetros que es funcional en ambos parámetros. (Probablemente, deberíamos convertirlo en una instancia de una clase Bifunctor, pero de todos modos ...) Podemos convertirlo en un Functor dos veces: una vez para el último parámetro ...

instance Functor (Bif x) where fmap f BNil = BNil fmap f (BCons x y b) = BCons x (f y) (fmap f b)

... y una vez por primera

instance Functor (Flip Bif y) where fmap f (Flip BNil) = Flip BNil fmap f (Flip (BCons x y b)) = Flip (BCons (f x) y (under Flip (fmap f) b))

donde under pf es una buena manera de decir op p . f . p op p . f . p op p . f . p .

No te digo mentiras: vamos a intentarlo.

someBif :: Bif Int Char someBif = BCons 1 ''a'' (BCons 2 ''b'' (BCons 3 ''c'' BNil))

y luego obtenemos

*Flip> fmap succ someBif BCons 1 ''b'' (BCons 2 ''c'' (BCons 3 ''d'' BNil)) *Flip> under Flip (fmap succ) someBif BCons 2 ''a'' (BCons 3 ''b'' (BCons 4 ''c'' BNil))

En estas circunstancias, realmente hay muchas maneras en que se puede ver lo mismo como un Functor , por lo que es correcto que tengamos que hacer un poco de ruido para decir a qué nos referimos. Pero el ruido no es mucho si eres sistemático al respecto.


La respuesta tonta que ya sabías es: cambia tus parámetros!

Para que GHC admita este tipo de cosas sin ningún ajuste adicional, necesitaría algo como las lambdas de nivel de tipo, que probablemente no se agregarán pronto. (Me encantaría estar equivocado al respecto)

instance Functor (/a -> SomeType2 a m) where -- fmap :: (a -> b) -> SomeType2 a m -> SomeType2 b m fmap f (SomeType2 lst m) = SomeType (map f lst) m

Dado que ya tenemos TypeSynonymInstances, podemos esperar un ParTipo de tipo de aplicación de tipo de aplicación parcial, algo más pronto que nunca.

type SomeType3 m a = SomeType2 a m instance Functor (SomeType m) where -- fmap :: (a -> b) -> SomeType3 m a -> SomeType3 m b -- or, synonymously: -- fmap :: (a -> b) -> SomeType2 a m -> SomeType2 a m fmap f (SomeType2 lst m) = SomeType (map f lst) m


Puede utilizar un envoltorio newtype que intercambia los parámetros de tipo. Pero luego obtiene un nuevo tipo y debe hacer una distinción entre el original y el tipo envuelto en su código.