functional programming - shadowhunters - ¿Entonces cuál es el punto?
idris significado (1)
¿Cuál es el propósito del tipo So ? Transliterando en Agda:
data So : Bool → Set where
oh : So true
So levanta una proposición booleana hasta una lógica. El documento introductorio de Oury y Swierstra, The Power of Pi, da un ejemplo de un álgebra relacional indexada por las columnas de las tablas. Tomar el producto de dos tablas requiere que tengan columnas diferentes, para las cuales usan So :
Schema = List (String × U) -- U is the universe of SQL types
-- false iff the schemas share any column names
disjoint : Schema -> Schema -> Bool
disjoint = ...
data RA : Schema → Set where
-- ...
Product : ∀ {s s''} → {So (disjoint s s'')} → RA s → RA s'' → RA (append s s'')
Estoy acostumbrado a construir términos de evidencia para las cosas que quiero probar acerca de mis programas. Parece más natural construir una relación lógica en los Schema para asegurar la desunión:
Disjoint : Rel Schema _
Disjoint s s'' = All (λ x -> x ∉ cols s) (cols s'')
where cols = map proj₁
Parece que tiene serias desventajas en comparación con un término de prueba "correcto": la coincidencia de patrones en oh no le proporciona ninguna información con la que pueda realizar otra verificación de tipo de término (¿lo hace?), Lo que significaría So valores pueden " Participa de manera útil en la prueba interactiva. Compare esto con la utilidad computacional de Disjoint , que se representa como una lista de pruebas de que cada columna en s'' no aparece en s .
Realmente no creo que la especificación So (disjoint s s'') es más simple de escribir que Disjoint s s'' , tiene que definir la función disjoint disjoint sin la ayuda del comprobador de tipos, y en cualquier caso, Disjoint paga sola cuando Quieres manipular la evidencia contenida en el mismo.
También soy escéptico de que So ahorra esfuerzo cuando estás construyendo un Product . Para dar un valor de So (disjoint s s'') , todavía tiene que hacer suficientes patrones de coincidencia en s y s'' para satisfacer el comprobador de tipos que, de hecho, son disjuntos. Parece un desperdicio desechar la evidencia así generada.
So parece difícil de manejar tanto para los autores como para los usuarios de código en el que se implementa. ''Entonces'', ¿bajo qué circunstancias querría usarlo?
Si ya tiene una b : Bool , puede convertirla en una proposición: So b , que es un poco más corto que b ≡ true . A veces (no recuerdo ningún caso real) no hay necesidad de molestarse con un tipo de datos adecuado, y esta solución rápida es suficiente.
Soparece tener serias desventajas en comparación con un término de prueba "correcto": la coincidencia de patrones enohno le proporciona ninguna información con la que pueda realizar otra verificación de tipo de término. Como corolario, los valores deSono pueden participar de manera útil en la prueba interactiva. Compare esto con la utilidad computacional deDisjoint, que se representa como una lista de pruebas de que cada columna ens''no aparece ens.
Le proporciona la misma información que Disjoint , solo necesita extraerla. Básicamente, si no hay incoherencia entre disjoint y Disjoint , entonces debería ser capaz de escribir una función So (disjoint s) -> Disjoint s utilizando la coincidencia de patrones, la recursión y la eliminación de casos imposibles.
Sin embargo, si ajustas un poco la definición:
So : Bool -> Set
So true = ⊤
So false = ⊥
So convierte en un tipo de datos realmente útil, porque x : So true se reduce a tt debido a la regla eta para ⊤ . Esto permite usar So como una restricción: en pseudo-Haskell podríamos escribir
forall n. (n <=? 3) => Vec A n
y si n está en forma canónica (es decir, suc (suc (suc ... zero)) ), entonces n <=? 3 n <=? 3 puede ser verificado por el compilador y no se necesitan pruebas. En Agda actual es
∀ {n} {_ : n <=? 3} -> Vec A n
Utilicé este truco en this respuesta (está {_ : False (m ≟ 0)} allí). Y supongo que sería imposible escribir una versión utilizable de la maquinaria descrita here sin esta simple definición:
Is-just : ∀ {α} {A : Set α} -> Maybe A -> Set
Is-just = T ∘ isJust
donde T es So en la biblioteca estándar de Agda.
Además, en presencia de argumentos de instancia, el tipo-as-a-data-type se puede usar como una restricción So -a-a:
open import Data.Bool.Base
open import Data.Nat.Base
open import Data.Vec
data So : Bool -> Set where
oh : So true
instance
oh-instance : So true
oh-instance = oh
_<=_ : ℕ -> ℕ -> Bool
0 <= m = true
suc n <= 0 = false
suc n <= suc m = n <= m
vec : ∀ {n} {{_ : So (n <= 3)}} -> Vec ℕ n
vec = replicate 0
ok : Vec ℕ 2
ok = vec
fail : Vec ℕ 4
fail = vec