对具有更多限制的默认值的可选参数强制使用更宽的类型 [英] Force a broader type for optional argument with more restrictive default value
本文介绍了对具有更多限制的默认值的可选参数强制使用更宽的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
有没有一种方法可以使可选参数f
足够灵活,使其具有类型'a -> 'b
,同时仍将其默认为identity
,因为identity
具有类型'a -> 'a
?
An earlier question以准确地说明我的问题开始:
我想定义一个接受可选参数的函数,该参数是 函数(‘a->’b)。默认值应为标识,该标识 实际上是(‘a->’a),但我看不出为什么不应该是 与更通用的(‘a->’b)兼容。但是,问题随后包括一个示例,该示例举例说明了一个更狭隘的问题。这个问题的答案回答了更狭隘的问题。以下是一般问题的简单化说明:
# let g1 ~f x = f x;;
val g1 : f:('a -> 'b) -> 'a -> 'b = <fun>
好的,这就是我想要的类型。但我希望f
默认为identity
函数。这应该是可能的,因为identity
具有'a -> 'b
类型,其中'b
是'a
。但它不起作用:
# let g2 ?(f=identity) x = f x;;
val g2 : ?f:('a -> 'a) -> 'a -> 'a = <fun>
在identity
上添加类型规范无济于事:
# let g3 ?(f=(identity:'a -> 'b)) x = f x;;
val g3 : ?f:('b -> 'b) -> 'b -> 'b = <fun>
编辑:在我发布这个问题后,我发现了this question,它实际上与我的问题非常相似。因此,如果您愿意,请将我的问题标记为副本。然而,这个问题的答案暗示,我想做的事情没有好的用处,这不是真的。以下是详细信息:
实际用例是从列表中选择一些元素的函数。可选的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
和tl
的用法有点不寻常。它可以更好地转换为惰性列表上下文。)
推荐答案
OCaml根本不支持此功能。不能编写类型根据是否传递了可选参数而细化的函数。
与链接问题中的一些答案不同,我同意这样做是合理的。实际上,键入类似Common Lisp的序列函数(使用:key
和:test
)似乎需要如下内容。但是,OCaml不是一种可以执行此操作的语言。
最合理的方法可能是编写两个函数,其中一个函数将访问器作为非可选参数,另一个函数提供identity
作为该参数:
let g f x = f x
let g_default x = g identity x
这只是有点笨拙,您不需要在g
中实现逻辑两次。但是,将此方法应用于多个可选参数的组合将变得很难看。
这篇关于对具有更多限制的默认值的可选参数强制使用更宽的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文