针对命令式香草JavaScript的ReasonML性能
免责声明:我是初学者 我最近开始使用ReasonML,我注意到它与普通JavaScript在性能上有很大的不同。下面是我针对一个简单的谜题解决函数的示例(谜题取自:) ReasonML针对命令式香草JavaScript的ReasonML性能,javascript,performance,reason,bucklescript,Javascript,Performance,Reason,Bucklescript,免责声明:我是初学者 我最近开始使用ReasonML,我注意到它与普通JavaScript在性能上有很大的不同。下面是我针对一个简单的谜题解决函数的示例(谜题取自:) ReasonML let head = str => switch (str) { | "" => "" | _ => String.sub(str, 0, 1) }; let tail = str => switch (str) { | "" => "" | _ =&g
let head = str =>
switch (str) {
| "" => ""
| _ => String.sub(str, 0, 1)
};
let tail = str =>
switch (str) {
| "" => ""
| _ => String.sub(str, 1, String.length(str) - 1)
};
let rec stringToList = str =>
switch (str) {
| "" => []
| _ => [[head(str)], tail(str) |> stringToList] |> List.concat
};
let rec findFloor = code =>
switch (head(code)) {
| "" => 0
| "(" => 1 + findFloor(tail(code))
| ")" => (-1) + findFloor(tail(code))
| _ => 0
};
let findFloorFold = code => {
let calc = (a, b) =>
switch (b) {
| "" => a
| "(" => a + 1
| ")" => a - 1
| _ => a
};
code |> stringToList |> List.fold_left(calc, 0);
};
JavaScript
const solve = code => {
let level = 0;
for (let i = 0, l = code.length; i < l; i++) {
const el = code[i];
if (el === "(") {
++level;
continue;
}
if (el === ")") {
--level;
continue;
}
}
return level;
};
const solve=code=>{
设水平=0;
for(设i=0,l=code.length;i
结果
- JavaScript:5ms
- ReasonML(递归):470ms
- ReasonML(非递归):7185ms
诚然,由于字符串到数组的转换,第二种解决方案(非rec)的速度很慢,但这是因为在ReasonML中,字符串不是由字符列表表示的 您可以合理地编写与JS中相同的命令式代码,并且实际速度更快(在我的计算机上提高30%): 这个递归解决方案几乎同样快:
let findFloorRecursiveNoList = code => {
let rec helper = (level, i) =>
if (i < String.length(code)) {
switch (code.[i]) {
| '(' => helper(level + 1, i + 1)
| ')' => helper(level - 1, i + 1)
| _ => failwith("invalid code")
}
} else {
level
};
helper(0, 0)
};
在非递归实现中,您可以使用该方法将函数应用于每个字符,而不是将字符串转换为列表,然后遍历列表吗?
string.iter
返回一个单元
类型,因此我希望能够累积操作结果(可能我误解了您的建议..)我认为,一般来说,由另一种语言生成的JavaScript比手动调整的JavaScript优化程度要低,但差别似乎太大了。生成的JavaScript似乎也有很多开销,比如加载库、List.
方法和很多函数调用,我只是把它扔了出去。我从来没有写过任何ReasonML,也没有写过任何标准ML已经将近20年了,但我似乎记得有一种方法可以将累加器作为传递给迭代器的函数的一部分。您的stringToList
转换似乎效率极低。我不知道ReasonML,我希望标准库中有一个本机转换函数(或者至少有一个字符串
到数组(char)
一个)。我会使用Str.split(regex“”)
thoughHmm,如果您对函数进行压力测试,您会发现JavaScript速度更快。(见reddit回复:)这很有趣,我们从Js版本慢了15%到Reason命令快了3%。同样,随着我们的扩展,递归虽然是这两种情况中最慢的,但它的性能提高了27%。@wegry“默认Curring”?@glennsl我的意思是使用[@bs]强制不修剪。不过,在这种情况下,codegen似乎不受影响。我想我不确定什么时候从bsb开始进行uncurring。是的,编译器既知道实现,也知道它的用法。它可以做这样的优化。在模块级,而不仅仅是在函数中。
let findFloorRecursiveNoList = code => {
let rec helper = (level, i) =>
if (i < String.length(code)) {
switch (code.[i]) {
| '(' => helper(level + 1, i + 1)
| ')' => helper(level - 1, i + 1)
| _ => failwith("invalid code")
}
} else {
level
};
helper(0, 0)
};
Reason, imperative: 19,246,043 ops/sec
Reason, recursive, no list: 18,113,602 ops/sec
JavaScript, imperative: 13,761,780 ops/sec
Reason, recursive, list: 481,426 ops/sec
Reason, folding, list: 239,761 ops/sec