【发布时间】:2015-12-31 19:46:24
【问题描述】:
我想知道为什么我们需要像“%identity”这样的函数,它和let a = a是一样的。使用它会不会提高性能?
我在我的程序中引入了幻像输入,多次调用标识函数来转换类型,很好奇“%identity”是否可以减少一些开销。
【问题讨论】:
我想知道为什么我们需要像“%identity”这样的函数,它和let a = a是一样的。使用它会不会提高性能?
我在我的程序中引入了幻像输入,多次调用标识函数来转换类型,很好奇“%identity”是否可以减少一些开销。
【问题讨论】:
%identity 函数是实现的一部分,而不是 OCaml 语言的一部分。它告诉编译器(本质上)无需将函数的参数更改为其返回值。换句话说,它告诉编译器继续使用相同的值,但改变其类型的想法。如果使用不当,它基本上会使 OCaml 类型系统的所有出色安全保证失效。此外,当然,它不能保证在该语言的任何其他实现中工作(包括 INRIA 编译器的未来版本)。
OCaml 编译器的内联功能应该已经保证不会为标识函数生成任何代码。所以我建议你继续使用它们。
更新
在 cmets 中回答一个不相关的问题......假设你有函数组合和恒等函数:
let (<<) f g x = f (g x)
let id x = x
然后是添加列表元素、相乘列表元素以及组合列表中所有函数的函数:
# let sum l = List.fold_right (+) l 0;;
val sum : int list -> int = <fun>
# let product l = List.fold_right ( * ) l 1;;
val product : int list -> int = <fun>
# let composition l = List.fold_right (<<) l id;;
val composition : ('a -> 'a) list -> 'a -> 'a = <fun>
例子:
# sum [2; 3; 5; 7];;
- : int = 17
# product [2; 4; 17];;
- : int = 136
# let mx = composition [(+) 1; ( * ) 10];;
val mx : int -> int = <fun>
# mx 2;;
- : int = 21
重点是0是加法,1是乘法,id是函数组合。 id 一直很有用,就像 0 和 1 一样。
【讨论】:
identity函数(不一定是%identity)?
let f x = x 吗?
使用 %identity 作为外部原语可以并且将减少与每次应用 (fun x -> x) 闭包时评估相关的开销。
OCaml 编译器对 % 原语进行特殊处理:bytecomp/translcore.ml 将每个原语与一个特殊的内置 AST 节点相关联(在 %identity 的情况下,它被映射到 Pidentity);编译器在节点上匹配并简化它所应用的表达式。在本机编译器的情况下,相关行是:
asmcomp/closure.ml 第 197 行和 ss.:简化 %identity 应用于参数本身的常量参数:
begin match p with
Pidentity -> make_const_int x
| Pnegint -> make_const_int (-x)
asmcomp/cmmgen.ml 第 1047 行和 ss.:将 %identity 简化为应用程序的 LHS 以直接评估参数:
match p with
(* Generic operations *)
Pidentity ->
transl arg
字节码编译器对原语有类似的简化规则。
【讨论】: