Я как-то новичок в Идрисе. Раньше я использовал немного agda, и у меня тяжелый опыт работы в GHC Haskell. Я пытаюсь понять, почему что-то, что работает в GHC Haskell, не работает в Идрисе. Следующий код не компилируется (idris version 0.12.3, nobuiltins, noprelude):
data Nat = S Nat | Z
plus : Nat -> Nat -> Nat
plus Z right = right
plus (S left) right = S (plus left right)
rightIdentityAlt : (n : Nat) -> n = (plus n Z)
rightIdentityAlt Z = Refl
rightIdentityAlt (S y) = case rightIdentityAlt y of
Refl => Refl
Это не выполняется со следующей ошибкой:
idris_binary.idr: 21: 3-7: При проверке левой стороны блока IdrisBinary.case в rightIdentityAlt на idris_binary.idr: 20: 31: Объединение y и плюс y Z приведет к бесконечному значению
Примерный эквивалентный код GXC haskell делает typecheck. Я могу получить версию Idris для typecheck, если я вместо этого использую:
cong : (x : Nat) -> (y : Nat) -> (f : Nat -> Nat) -> x = y -> f x = f y
cong _ _ _ Refl = Refl
rightIdentity : (n : Nat) -> n = (plus n Z)
rightIdentity Z = Refl
rightIdentity (S x) = cong x (plus x Z) S (rightIdentity x)
Я думаю, что причина, по которой rightIdentityAlt
работает в GHC Haskell, но не в Идрисе, имеет дело с различием в том, как унификация работает на двух языках. В GHC Haskell унификации, полученные из сопоставления шаблонов на GADT, просто распространяются повсюду, но в Idris кажется, что вам нужно уточнить исходные типы с помощью предложения with
. Вот моя попытка сделать это:
rightIdentityAlt : (n : Nat) -> n = (plus n Z)
rightIdentityAlt Z = Refl
rightIdentityAlt (S y) with (rightIdentityAlt y)
rightIdentityAlt (S y) | Refl {A = Nat} {x = y} = Refl
Blast. Еще ничего хорошего. Теперь мы потеряли равенство, которое мы изначально пытались доказать:
idris_binary.idr:26:20:When checking left hand side of with block in IdrisBinary.rightIdentityAlt:
Type mismatch between
plus y Z (Inferred value)
and
y (Given value)
Holes: IdrisBinary.rightIdentityAlt
Я понимаю, что прагматичный ответ заключается только в том, чтобы переписать это с помощью cong
или для чего-то, связанного с тактикой, но я действительно хочу понять, почему способ, которым я хочу писать rightIdentityAlt
, не работает. Согласование шаблонов на =
не дает доказательств в объеме, как я ожидал бы. Есть ли способ заставить это сделать это, или есть что-то принципиально неправильное в этом подходе в Идрисе?