Si. Esto se llama "estilo de aprobación de diccionario". A veces, cuando estoy haciendo algunas cosas especialmente difíciles, necesito desechar una clase de texto y convertirla en un diccionario, porque la aprobación del diccionario es más potente 1 , pero a menudo bastante engorrosa, lo que hace que el código conceptual simple parezca bastante complicado. A veces uso el estilo de aprobación de diccionario en idiomas que no son Haskell para simular clases de tipos (pero he aprendido que, por lo general, no es una idea tan buena como parece).
Por supuesto, cada vez que hay una diferencia en el poder expresivo, hay una compensación. Si bien puede usar una API determinada de más maneras si está escrita con DPS, la API obtiene más información si no puede. Una forma en que esto aparece en la práctica es en Data.Set
, que se basa en el hecho de que solo hay un Ord
diccionario por tipo. Las Set
tiendas de sus elementos ordenados según Ord
, y si se construye un conjunto con un diccionario, y luego inserta un elemento utilizando una diferente, ya que sería posible con DPS, se podría romper Set
's invariante y hacer que se caiga. Este problema de singularidad puede mitigarse utilizando un fantasma existencialescriba para marcar el diccionario, pero, una vez más, a costa de una complejidad bastante molesta en la API. Esto también se muestra más o menos de la misma manera en la Typeable
API.
El bit de singularidad no aparece muy a menudo. En qué clases de tipos es excelente escribir código para usted. Por ejemplo,
catProcs :: (i -> Maybe String) -> (i -> Maybe String) -> (i -> Maybe String)
catProcs f g = f <> g
que toma dos "procesadores" que toman una entrada y pueden dar una salida, y los concatena, aplanándolos Nothing
, tendría que escribirse en DPS algo como esto:
catProcs f g = (<>) (funcSemi (maybeSemi listSemi)) f g
Esencialmente tuvimos que deletrear el tipo en el que lo estamos usando nuevamente, a pesar de que ya lo deletreamos en la firma de tipo, e incluso eso era redundante porque el compilador ya conoce todos los tipos. Debido a que solo hay una forma de construir un determinado Semigroup
en un tipo, el compilador puede hacerlo por usted. Esto tiene un efecto de tipo "interés compuesto" cuando comienzas a definir muchas instancias paramétricas y a usar la estructura de tus tipos para calcular por ti, como en los Data.Functor.*
combinadores, y esto se usa para un gran efecto con el deriving via
que esencialmente puedes obtener todos los estructura algebraica "estándar" de su tipo escrita para usted.
Y ni siquiera me hagas comenzar con MPTC y fundeps, que retroalimentan la información en la verificación de tipos e inferencia. Nunca he intentado convertir tal cosa a DPS; sospecho que implicaría pasar muchas pruebas de igualdad de tipos, pero en cualquier caso, estoy seguro de que sería mucho más trabajo para mi cerebro de lo que estaría cómodo con.
-
1 U alvo que utilizar reflection
en cuyo caso se convierten en equivalente en potencia - pero reflection
también puede ser complicado de usar.