Estoy buscando un concepto en teoría de tipos que estoy seguro de que probablemente ha sido explorado, pero no sé el nombre detrás.
Consideremos un lenguaje similar a ML con tipos de producto y suma y un sistema de tipos similar a Hindley-Milner. Usaré la sintaxis OCaml.
Me pregunto cómo dos valores diferentes pueden ser diferentes.
Utilizar
Mi caso de uso es escribir mensajes de error "más claros" en una biblioteca tipo xUnit: si dos valores son diferentes cuando se esperaba que fueran iguales, esto puede ayudar a construir un mensaje mejor y más claro:
Antes de:
Los valores difieren: esperado
{x = [1;2;3;4], y = "a long string"}
, conseguido{x = [1;2;3;3], y = "a long string"}
Después:
Los valores difieren: en la posición
.x[3]
, esperado 4, obtuve 3.
(puede haber una relación con lentes funcionales ya que finalmente estamos construyendo una lente a un valor menor que difiere).
Tipos de productos
Por ejemplo:
type p =
{ x : int
; y : string
}
La igualdad se puede definir como:
let equal a b =
equal_int a.x b.x && equal_string a.y b.y
Pero también es posible reificar las diferencias:
type delta_p =
| Equal
| Diff_x of int * int
| Diff_y of string * string
let diff_p a b =
if not (equal_int a.x b.x) then
Diff_x (a.x, b.x)
else if not (equal_string a.y b.y) then
Diff_y (a.y, b.y)
else
Equal
(puede tener sentido definir un delta_int
tipo int * int
para mostrar que es recursivo)
Tipos de suma
Para un tipo de suma hay más formas de diferenciarse: tener un constructor diferente o un valor diferente
type s = X of int | Y of string
type ctor_s =
| Ctor_X
| Ctor_Y
type delta_s =
| Equal
| Diff_ctor of ctor_s * ctor_s
| Diff_X of int * int
| Diff_Y of string * string
let diff_s a b = match (a, b) with
| X xa, X xb ->
if equal_int xa xb then
Equal
else
Diff_X (xa, xb)
| (* Y case similar *)
| X _, Y _ -> Diff_ctor (Ctor_X, Ctor_Y)
| Y _, X _ -> Diff_ctor (Ctor_Y, Ctor_X)
¿Cómo se llama este concepto? ¿Dónde puedo aprender más sobre esto?
¡Gracias!
fuente
Respuestas:
Creo que está buscando una variante tipificada de antiunificación . La antiunificación puede describirse como sigue. Primero, supongamos que tenemos una gramática de términos como sigue:
Aquí,
()
y(t, t)
denota unidades y pares,C t
es un término con un constructor principal, yX
es una variable de término, que podría sustituirse por cualquier término.El problema de antiunificación dice, si da dos términos
t1
yt2
, ¿cuál es el término menos generalt
para que haya sustitucioness1
ys2
tal ques1(t) = t1
ys2(t) = t2
?Como ejemplo concreto, dados dos términos
el algoritmo anti-unificación devolvería el anti-unificador
porque las sustituciones
s1 = [X:3, Y:1]
ys2 = [X:1, Y:3]
aplicadast
te daríant1
y tet2
devolverían. Como comentario aparte, necesitábamos especificar "menos general" porque de lo contrario:con las sustituciones
s1 = [Z:t1]
ys2 = [Z:t2]
haría el truco.gen
Aumentando este algoritmo para devolver las dos sustituciones
s1
ys2
lo dejo como ejercicio.fuente