haskell - Combinar clases Data.Dynamic y type
typeclass (1)
Dada una variable de tipo Dynamic
, ¿es posible aprovechar las clases de tipos de la variable interna sin condicionar el tipo exacto? Por ejemplo, digamos que quiero escribir una función prettyShow
. Si el tipo interno es una instancia de Show
, entonces deberíamos usar esa instancia; de lo contrario, deberíamos usar la instancia de la clase Dynamic
. En el código, esto podría verse así:
prettyShow :: Dynamic -> String
prettyShow x = case fromDynamic x :: (forall a. Show a => Maybe a) of
Nothing -> show x
Just y -> show y
Editar: dado que parece que esto no se puede hacer directamente, ¿cuál es una buena solución que se puede hacer?
Esto se puede hacer usando la implementación de Dynamic
en la biblioteca open-typerep (si acepta usar programación genérica y muchas extensiones GHC).
{-# LANGUAGE TypeOperators #-}
import Data.TypeRep
type Types = BoolType :+: IntType :+: ListType
x, y :: Dynamic Types
x = toDyn [False,True]
y = toDyn [1, 2 :: Int]
test1 = show x
test2 = show y
La definición de show
es simple, y puede usar la biblioteca para definir otras funciones sobre valores dinámicos.
En el ejemplo anterior utilicé un tipo de universo de tipo cerrado. Pero al usar trucos a la Carta de tipos de datos también puede definir funciones para universos abiertos. Por ejemplo, show
está abierto.
Actuación
Un punto de referencia simple muestra que esta Dynamic
es 2-3 veces más lenta que Data.Dynamic
en la base
para el universo de tipo pequeño utilizado anteriormente. Aumentar el universo a 30 constructores de tipo lo hace un poco más de 10 veces más lento.
Derivado automático para nuevos tipos
open-typerep
admite la creación de universos a partir de un pequeño número de tipos de representación predefinidos. En principio, debería ser posible utilizar TemplateHaskell para autoderivar representaciones para nuevos tipos, pero será difícil generar las instancias adecuadas para Witness
y PWitness
ya que dependen de qué otras instancias están disponibles. (El Witness
se usa, por ejemplo, en la instancia Show
para Dynamic
).