在 Idris 中对 "higher-kinded" 类型进行参数化
Parametrising over "higher-kinded" types in Idris
我刚开始玩 Idris,并尝试将一些 Haskell 机器塞进其中:
namespace works
data Auto a b = AutoC (a -> (b, Auto a b))
const_auto : b -> Auto a b
const_auto b = AutoC (\_ => (b, const_auto b))
但是,我现在想将 Auto a b
概括为 AutoM m a b
以获取一个额外的参数,以便它可以单子生成其输出,其中 m
是单子。我的直觉是 m
的类型是 Type -> Type
,但随后类型检查器抱怨说它与 (Type, Type) -> Type
不匹配。所以我试着让它多一点多态:
namespace doesntwork
data AutoM : {x : Type } -> (m : x -> Type) -> (a : Type) -> (b : Type) -> Type where
AutoMC : (a -> m (b, AutoM m a b)) -> AutoM m a b
data Identity a = IdentityC a
Auto : Type -> Type -> Type
Auto = AutoM Identity
这至少是类型检查。但是当我尝试时:
const_auto : Monad m => {m : x -> Type } -> {a : Type} -> b -> AutoM m a b
const_auto b = AutoMC (\_ => return (b, const_auto b))
然而,这并不好:
When elaborating right hand side of Stream.doesntwork.const_auto:
When elaborating an application of function Prelude.Monad.return:
Can't unify
(A, B) (Type of (a, b))
with
(b, AutoM m4 a b) (Expected type)
而且我无法理解类型错误。当 const_auto
的定义中没有任何地方使用 a
时,为什么要提到 (a, b)
的类型?我觉得 AutoM
本身的定义已经有问题,但我真的不知道为什么或如何。
当你的直觉告诉你 m
作为一个单子时,你是对的,它的类型应该是 Type -> Type
。这里的问题是 (,)
is overloaded 意味着 Pair
类型构造函数和 mkPair
数据构造函数,而 Idris 的详细说明者做出了错误的选择。
通过显式选择 Pair
,您可以修正定义:
data AutoM : (m : Type -> Type) -> (a : Type) -> (b : Type) -> Type where
AutoMC : (a -> m (Pair b (AutoM m a b))) -> AutoM m a b
现在,如果您这样做,您会收到另一条神秘消息:
Auto.idr:18:14:
When elaborating right hand side of Main.doesntwork.const_auto:
Can't resolve type class Monad m3
Metavariables: Main.doesntwork.const_auto
这里的问题是您在 const_auto
的类型注释中引入了隐式 m
,这与 已经引入的 不同约束 Monad m =>
,所以 Idris 找不到这个新 m
的 Monad
实例。解决方案是根本不引入它(提到 m
的约束足以使其在范围内),如下所示:
const_auto : Monad m => {a : Type} -> b -> AutoM m a b
我刚开始玩 Idris,并尝试将一些 Haskell 机器塞进其中:
namespace works
data Auto a b = AutoC (a -> (b, Auto a b))
const_auto : b -> Auto a b
const_auto b = AutoC (\_ => (b, const_auto b))
但是,我现在想将 Auto a b
概括为 AutoM m a b
以获取一个额外的参数,以便它可以单子生成其输出,其中 m
是单子。我的直觉是 m
的类型是 Type -> Type
,但随后类型检查器抱怨说它与 (Type, Type) -> Type
不匹配。所以我试着让它多一点多态:
namespace doesntwork
data AutoM : {x : Type } -> (m : x -> Type) -> (a : Type) -> (b : Type) -> Type where
AutoMC : (a -> m (b, AutoM m a b)) -> AutoM m a b
data Identity a = IdentityC a
Auto : Type -> Type -> Type
Auto = AutoM Identity
这至少是类型检查。但是当我尝试时:
const_auto : Monad m => {m : x -> Type } -> {a : Type} -> b -> AutoM m a b
const_auto b = AutoMC (\_ => return (b, const_auto b))
然而,这并不好:
When elaborating right hand side of Stream.doesntwork.const_auto:
When elaborating an application of function Prelude.Monad.return:
Can't unify
(A, B) (Type of (a, b))
with
(b, AutoM m4 a b) (Expected type)
而且我无法理解类型错误。当 const_auto
的定义中没有任何地方使用 a
时,为什么要提到 (a, b)
的类型?我觉得 AutoM
本身的定义已经有问题,但我真的不知道为什么或如何。
当你的直觉告诉你 m
作为一个单子时,你是对的,它的类型应该是 Type -> Type
。这里的问题是 (,)
is overloaded 意味着 Pair
类型构造函数和 mkPair
数据构造函数,而 Idris 的详细说明者做出了错误的选择。
通过显式选择 Pair
,您可以修正定义:
data AutoM : (m : Type -> Type) -> (a : Type) -> (b : Type) -> Type where
AutoMC : (a -> m (Pair b (AutoM m a b))) -> AutoM m a b
现在,如果您这样做,您会收到另一条神秘消息:
Auto.idr:18:14:
When elaborating right hand side of Main.doesntwork.const_auto:
Can't resolve type class Monad m3
Metavariables: Main.doesntwork.const_auto
这里的问题是您在 const_auto
的类型注释中引入了隐式 m
,这与 已经引入的 不同约束 Monad m =>
,所以 Idris 找不到这个新 m
的 Monad
实例。解决方案是根本不引入它(提到 m
的约束足以使其在范围内),如下所示:
const_auto : Monad m => {a : Type} -> b -> AutoM m a b