强制使用更宽泛的类型作为可选参数,具有更严格的默认值

时间:2018-01-21 05:31:48

标签: ocaml

是否有办法让可选参数f具有足够的灵活性以使其具有'a -> 'b类型,但仍然将其默认为identity,因为identity具有类型{{ 1}}?

An earlier question 通过陈述我的问题开始:确切地说:

  

我想定义一个接受可选参数的函数   一个函数(' a - >' b)。默认值应该是标识,即   实际上(' a - >' a),但我认为没有理由不应该这样做   与更一般的(' a - >' b)兼容。

然而,问题包括一个举例说明较窄问题的例子。该问题的答案对较窄的问题作出了回应。以下是一般问题的简单说明:

'a -> 'a

好的,这就是我想要的类型。但我希望# let g1 ~f x = f x;; val g1 : f:('a -> 'b) -> 'a -> 'b = <fun> 默认使用f功能。这应该是可能的,因为identity的{​​{1}}类型为identity'a -> 'b'b。但它不起作用:

'a

# let g2 ?(f=identity) x = f x;; val g2 : ?f:('a -> 'a) -> 'a -> 'a = <fun> 上添加类型规范并没有帮助:

identity
编辑:在我发布这个问题之后,我发现了this question,这与我的问题非常接近。因此,如果您愿意,请将我的问题标记为重复。然而,这个问题的答案意味着对我想做的事情没有好用,而事实并非如此。以下是详细信息:

实际用例是一个从列表中选择一些元素的函数。可选的# let g3 ?(f=(identity:'a -> 'b)) x = f x;; val g3 : ?f:('b -> 'b) -> 'b -> 'b = <fun> 参数允许从每个元素中提取一些数据,并使用该数据来决定是否在结果中包含该特定的列表元素。当整个元素选择元素时,f应为f。我试图定义的实际函数是用于惰性列表。这是列表的简化版本,identityL的别名:

List

简单使用:

let select ?(accessor=identity) keys vals =
  let rec sel ks vs =
    if ks = [] || vs = [] then []
    else let k, v = L.hd ks, L.hd vs in
         let v_key = accessor v in
         if k = v_key then v::(sel (L.tl ks) (L.tl vs))
         else if k > v_key then sel ks (L.tl vs) (* let vs catch up *)
         else sel (L.tl ks) vs                   (* let ks catch up *)
  in sel keys vals

更常见的用法是,# let vs = Batteries.List.range 1 `To 100;; # let ks = [4; 10];; # select ks vs;; - : int list = [4; 10] 的元素是具有关键字段的整数记录。然后ks函数将从记录类型映射到accessor

(是的,我知道使用inthd有点不寻常。它会更好地转换为惰性列表上下文。)

2 个答案:

答案 0 :(得分:3)

OCaml根本不支持这一点。根据是否已传递可选参数,您无法编写具有精炼类型的函数。

与链接问题中的一些答案不同,我同意这是一个合理的想法。实际上,输入Common Lisp的序列函数(使用qtCPUBar::qtCPUBar(int i) { ... _i = i; connect(timer, QTimer::timeout, this, [this]() { showCPU(_i); }); ... } :key)似乎需要这样的东西。但是,OCaml不是一种可以完成它的语言。

最合理的方法可能是编写两个函数,其中一个函数将一个访问器作为非可选参数,另一个函数将:test作为该参数提供:

identity

这只是有点笨拙,你不需要在let g f x = f x let g_default x = g identity x 中实现两次逻辑。但是,将此方法应用于多个可选参数的组合将变得很难看。

答案 1 :(得分:2)

我认为看待这个的方法是想象你的功能会有什么类型。你似乎要求这种类型:

?f:('a -> 'b) -> 'a -> 'b

但是,这并不意味着当您省略可选参数时,类型将恢复为'a -> 'a

相反,此类型的含义是,如果省略可选参数,则您具有类型'a -> 'b的函数。但是没有类型为'a -> 'b的格式良好的函数。这只能是永不返回(或类似)的函数类型。

我对此的看法是,OCaml类型系统无法代表您想要的功能,即使它确实有意义。

相关问题