首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >外部参数GADT

外部参数GADT
EN

Stack Overflow用户
提问于 2015-10-26 16:51:48
回答 1查看 247关注 0票数 2

GADT允许某种形式的动态键入:

代码语言:javascript
复制
type _ gadt =
  | Int: int -> int gadt
  | Float: float -> float gadt

let f: type a. a gadt -> a = function
  | Int x -> x + 1
  | Float x -> x +. 1.

我希望能够进行同样的分派,但使用参数化的类型,从外部访问小工具的参数。如果参数是普遍量化的,或者是固定的,这是很容易的:

代码语言:javascript
复制
type (_,_) container = 
  | List: 'a list -> ('a,'a list) container

let f : type a b. (a,b) container -> b = fun (List l) -> l
let g : type a b. a -> (a, b) container -> b = fun x (List l) -> x::l
let h : type b. (int, b) container -> b = fun (List l) ->  1::l

但是,如果参数上存在其他形式的约束,则不起作用:

代码语言:javascript
复制
class ['a] ko (x:'a) = object 
    method m : type b. ('a, b) container -> b = fun (List l) -> x::l
end

我得到了错误:类型构造函数a#0将转义它的作用域。我想这是由于外部限制,没有充分了解领域。

我找到的唯一解决方案是使用更高的模块:

代码语言:javascript
复制
open Higher
module Higher_List = Newtype1 (struct type 'a t = 'a list end)
type ('a,_) container = List: 'a list -> ('a, Higher_List.t) container

class ['a] c (x:'a) = object
    method m : type b. b container -> ('a,b) app = fun (List l) -> Higher_List.inj(x::l)
end

然而,这个解决方案远非十全十美:首先,它是冗长的,到处都是inj和prj,更重要的是,它有许多限制:'a参数不能有约束,也不能有方差……

有没有人知道更好的解决方案?

编辑

经过一些思考,Drup解决方案是有效的,但它必须小心!在我的全部问题中(而不是这个问题中的玩具程序),我需要在方法定义中访问self。所以回到Drup解决方案,我必须将self传递给中间函数,要做到这一点,我必须给它一个类型。所以我必须先声明一个类类型..。

代码语言:javascript
复制
class type ['a] c_type = object
    method m: ('a, 'b) container -> 'b
end

let cons : type a b. a c_type -> a -> (a,b) container  -> b =
    fun self x (List l) -> x::l

class ['a] c (x:'a) = object(self: 'a #c_type)
    method m = cons (self :> 'a c_type) x
end

但是,如果类c'a有限制,这就行不通:cons的类型将无效,因为a必须是通用量化的,但在a c_type中有禁忌。解决方案是在不受'a约束的情况下编写'a。然而,请注意,这意味着大量重写。在许多情况下,仅仅忽略约束并不足以使其消失:所有的使用都必须是无约束的.

因此,最终的解决方案如下:

代码语言:javascript
复制
type (_,_) container = 
  | List: 'a list -> ('a,'a list) container

class type ['a] c_type = object
    (* no constraint on 'a, and take care of its usage ! *)
    method m: ('a, 'b) container -> 'b
end

let cons : type a b. a c_type -> a -> (a,b) container  -> b =
    fun self x (List l) -> x::l (* in real code, self is used... *)

class ['a] c (x:'a) = object(self: 'a #c_type)
    constraint 'a = < .. > (* well just for the example *)
    method m = cons (self :> 'a c_type) x
end
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-10-26 17:29:55

当你可以做简单的事情时,为什么要尝试复杂呢?

代码语言:javascript
复制
type (_,_) container =
  | List: 'a list -> ('a,'a list) container

let cons : type a b. a -> (a, b) container -> b = fun x (List l) -> x::l

class ['a] ko (x:'a) = object
    method m : type b. ('a, b) container -> b = cons x
end

这种构造很复杂,因为局部抽象类型的放置很重要。在您的示例中,您希望在类的外层(对于a类型)设置一个本地抽象类型,这是不可能的。使一个中间的,适当的抽象,功能通常是有帮助的。

另外,不要使用higher。这证明了你可以在模块系统中编码HKT,而不是鼓励你去做。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33351239

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档