能否让GHC支持数学归纳以推导无穷元组的Semigroup实例?
实现方案与原理说明
你要的无穷半群直积实例完全可以实现,两种可行方案如下:
方案1:直接使用UndecidableInstances(推荐)
你对UndecidableInstances的顾虑是多余的:这个扩展只是关闭了GHC默认的实例终止性静态检查,只要实例定义的归纳结构是明确的,就不会触发GHC死循环。
你当前的OmegaTuple是无穷递归结构,实际代码中永远不会用到完全展开的无穷长元组,所有操作都只会按需展开有限层,这里使用UndecidableInstances是完全安全的。
完整可运行代码:
{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE QuantifiedConstraints #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} -- 新增这一行即可 import GHC.TypeNats infixr 5 :!! data OmegaTuple (t :: Nat -> *) (n :: Nat) = t n :!! OmegaTuple t (n+1) instance (Semigroup (t n), Semigroup (OmegaTuple t (n+1))) => Semigroup (OmegaTuple t n) where (x :!! xs) <> (y :!! ys) = x <> y :!! xs <> ys
方案2:自定义归纳自然数绕开类型族限制
你第二次尝试的报错原因是:GHC不允许在全称约束的实例头中出现类型族应用,内置Nat的加法+本身是类型族,所以触发了报错。
你可以自定义归纳结构的自然数类型(无需类型族计算),就能不用UndecidableInstances实现需求:
{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE QuantifiedConstraints #-} {-# LANGUAGE TypeOperators #-} -- 自定义归纳自然数,无类型族计算 data Nat' = Z | S Nat' infixr 5 :!! data OmegaTuple (t :: Nat' -> *) (n :: Nat') = t n :!! OmegaTuple t ('S n) -- 不需要UndecidableInstances即可通过编译 instance (Semigroup (t n), forall k. Semigroup (t k) => Semigroup (t ('S k))) => Semigroup (OmegaTuple t n) where (x :!! xs) <> (y :!! ys) = x <> y :!! xs <> ys
总结
GHC完全可以识别归纳逻辑完成这类实例推导,要么在安全场景下使用UndecidableInstances,要么用自定义归纳ADT绕开类型族限制即可。
内容的提问来源于stack exchange,提问作者Dannyu NDos
相关产品推荐
相关产品推荐

