是否有办法让可选参数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
。我试图定义的实际函数是用于惰性列表。这是列表的简化版本,identity
是L
的别名:
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
。
(是的,我知道使用int
和hd
有点不寻常。它会更好地转换为惰性列表上下文。)
答案 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类型系统无法代表您想要的功能,即使它确实有意义。