variable print functions custom argument haskell typeclass

functions - print variable haskell



¿Es posible tener una instancia de clase de tipo "local"? (1)

Lo que quiero decir es definir una instancia de una clase de tipo que se aplica en un ámbito local ( let o where ) en una función. Más importante aún, quiero que las funciones en esta instancia sean cierres, es decir, poder cerrar sobre las variables en el ámbito léxico donde se define la instancia (lo que significa que la instancia posiblemente funcione de manera diferente la próxima vez que se llame a la función en la que está). ).

Puedo darle un caso de uso simplificado para esto. Supongamos que tengo una función que opera en un tipo basado en una clase de tipo. En este ejemplo, uso la cuadratura, que funciona con cualquier tipo que instale a Num (sí, la cuadratura es muy simple y se puede volver a implementar fácilmente, pero es algo que podría ser más complicado). Necesito poder usar la función existente tal como está (sin cambiarla ni volver a implementarla).

square :: Num a => a -> a square x = x * x

Ahora, supongamos que deseo usar esta operación en aritmética modular, es decir, suma, multiplicación, etc. mod algún número. Esto sería fácil de implementar para cualquier base de módulo fija, pero quiero tener algo genérico que pueda reutilizar para diferentes bases de módulo. Quiero poder definir algo como esto:

newtype ModN = ModN Integer deriving (Eq, Show) -- computes (x * x) mod n squareModN :: squareModN x n = let instance Num ModN where ModN x * ModN y = ModN ((x * y) `mod` n) -- modular multiplication _ + _ = undefined -- the rest are unimplemented for simplicity negate _ = undefined abs _ = undefined signum _ = undefined fromInteger _ = undefined in let ModN y = square (ModN x) in y

El punto de esto es que necesito usar la función desde arriba ( square ) que requiere que su argumento sea un tipo que sea una instancia de una cierta clase de tipo. Defino un nuevo tipo y lo convierto en una instancia de Num ; sin embargo, para que realice la aritmética de módulo correctamente, depende del módulo base n , que, debido al diseño genérico de esta función, podría cambiar de una llamada a otra. Deseo definir las funciones de instancia como el tipo de "devoluciones de llamada" de una sola vez (si lo desea) para que la función square personalice la forma en que realiza las operaciones esta vez (y solo esta vez).

Una solución podría ser integrar las "variables de cierre" directamente en el mismo tipo de datos (es decir, ModN (x, n) para representar el número y la base a la que pertenece), y las operaciones solo pueden extraer esta información de los argumentos. Sin embargo, esto tiene varios problemas: 1) Para las funciones de múltiples argumentos (por ejemplo, (*) ), debería comprobar en tiempo de ejecución que esta información coincida, lo cual es feo; y 2) la instancia podría contener "valores" de 0 argumentos que me gustaría depender de las variables de cierre, pero que, como no contienen argumentos, no pueden extraerlos de los argumentos.


La extensión propuesta tiene el mismo problema demostrado en esta respuesta anterior mía; puede usar las instancias locales para crear dos Map con el mismo tipo de clave pero diferentes instancias de Ord , lo que hace que todos los invariantes se caigan.

Sin embargo, el paquete de reflection permite definir un tipo de ModN tipo: usted define una instancia única con una restricción Reifies y activa la instancia para una n particular con reify . (Creo que los parámetros implícitos también harían esto posible, pero esa extensión rara vez se usa).