我最近发现类型孔与样张上的图案匹配相结合,在Haskell中提供了非常好的Agda式体验。例如:
{-# LANGUAGE
DataKinds, PolyKinds, TypeFamilies,
UndecidableInstances, GADTs, TypeOperators #-}
data (==) :: k -> k -> * where
Refl :: x == x
sym :: a == b -> b == a
sym Refl = Refl
data Nat = Zero | Succ Nat
data SNat :: Nat -> * where
SZero :: SNat Zero
SSucc :: SNat n -> SNat (Succ n)
type family a + b where
Zero + b = b
Succ a + b = Succ (a + b)
addAssoc :: SNat a -> SNat b -> SNat c -> (a + (b + c)) == ((a + b) + c)
addAssoc SZero b c = Refl
addAssoc (SSucc a) b c = case addAssoc a b c of Refl -> Refl
addComm :: SNat a -> SNat b -> (a + b) == (b + a)
addComm SZero SZero = Refl
addComm (SSucc a) SZero = case addComm a SZero of Refl -> Refl
addComm SZero (SSucc b) = case addComm SZero b of Refl -> Refl
addComm sa@(SSucc a) sb@(SSucc b) =
case addComm a sb of
Refl -> case addComm b sa of
Refl -> case addComm a b of
Refl -> Refl
非常好的是我可以用类型孔替换Refl -> exp
构造的右侧,并且我的洞目标类型用证明更新,就像{{1}一样在阿格达形成。
然而,有时洞无法更新:
rewrite
另外,即使目标类型不一定排在校对内,如果我从Agda粘贴整个东西,它仍然可以检查:
(+.) :: SNat a -> SNat b -> SNat (a + b)
SZero +. b = b
SSucc a +. b = SSucc (a +. b)
infixl 5 +.
type family a * b where
Zero * b = Zero
Succ a * b = b + (a * b)
(*.) :: SNat a -> SNat b -> SNat (a * b)
SZero *. b = SZero
SSucc a *. b = b +. (a *. b)
infixl 6 *.
mulDistL :: SNat a -> SNat b -> SNat c -> (a * (b + c)) == ((a * b) + (a * c))
mulDistL SZero b c = Refl
mulDistL (SSucc a) b c =
case sym $ addAssoc b (a *. b) (c +. a *. c) of
-- At this point the target type is
-- ((b + c) + (n * (b + c))) == (b + ((n * b) + (c + (n * c))))
-- The next step would be to update the RHS of the equivalence:
Refl -> case addAssoc (a *. b) c (a *. c) of
Refl -> _ -- but the type of this hole remains unchanged...
您是否有任何想法为什么会发生这种情况(或者我如何以强有力的方式进行证明重写)?
答案 0 :(得分:1)
如果要生成所有可能的此类值,则可以使用提供的或指定的边界编写一个函数来执行此操作。
很有可能使用类型级别的教会数字或其他类似的东西来强制创建这些,但对于你可能想要/需要的东西来说,这几乎肯定是太多了。
这可能不是你想要的(即“除了使用只是(x,y),因为z = 5 - x - y”)但它比尝试对类型级别有某种强制限制更有意义允许有效值。
答案 1 :(得分:-3)
这是因为值是在运行时确定的。它可以根据运行时输入的内容进行值转换,因此它假定孔已经更新。