- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在移植一些严重依赖延迟评估的Python代码。这可以通过thunks完成。更具体地说,任何需要延迟评估的Python表达式<expr>
都被封装在Python“lambda表达式”中,即lambda:<expr>
。
AFAIK,与此最接近的JavaScript等效项是function(){return <expr>}
。
由于我正在使用的代码在这样的重击中绝对泛滥成灾,因此,我想尽可能使它们的代码更简洁。这样做的原因不仅是为了保存字符(在使用JS时不可忽略的考虑),而且还使代码更具可读性。要了解我的意思,请比较以下标准JavaScript形式:
function(){return fetchx()}
\fetchx()
fetchx()
表达式在打印上被周围的
function(){return
...
}
遮盖。在第二种形式1中,仅一个(
\
)字符用作“延迟评估标记”。我认为这是最佳方法。
eval
模拟延迟评估。 eval
(上面的选项1),但是FWIW在下面给出了一个有关此选项的说明。
C
,表示“CODE”)的工厂方法来减少例如
function(){return fetchx()}
C('fetchx()')
C
和辅助函数
maybe_eval
:
var C = (function () {
function _delayed_eval(code) { this.code = code; }
_delayed_eval.prototype.val = function () { return eval(this.code) };
return function (code) { return new _delayed_eval(code) };
})();
var maybe_eval = (function () {
var _delayed_eval = C("").constructor;
return function (x) {
return x instanceof _delayed_eval ? x.val() : x;
}
})();
get
函数和
lazyget
函数之间的以下比较显示了如何使用以上内容。
obj
,键
key
和默认值,并且如果
obj[key]
中存在
key
,则它们都应返回
obj
,否则返回默认值。
lazyget
的默认值可以是thunk,如果是,则只有
key
不在
obj
中时,它的值才会被求值。
function get(obj, key, dflt) {
return obj.hasOwnProperty(key) ? obj[key] : dflt;
}
function lazyget(obj, key, lazydflt) {
return obj.hasOwnProperty(key) ? obj[key] : maybe_eval(lazydflt);
}
function slow_foo() {
++slow_foo.times_called;
return "sorry for the wait!";
}
slow_foo.times_called = 0;
var someobj = {x: "quick!"};
console.log(slow_foo.times_called) // 0
console.log(get(someobj, "x", slow_foo())); // quick!
console.log(slow_foo.times_called) // 1
console.log(lazyget(someobj, "x",
C("slow_foo().toUpperCase()"))); // quick!
console.log(slow_foo.times_called) // 1
console.log(lazyget(someobj, "y",
C("slow_foo().toUpperCase()"))); // SORRY FOR THE WAIT!
console.log(slow_foo.times_called) // 2
console.log(lazyget(someobj, "y",
"slow_foo().toUpperCase()")); // slow_foo().toUpperCase()
console.log(slow_foo.times_called) // 2
0
quick!
1
quick!
1
SORRY FOR THE WAIT!
2
slow_foo().toUpperCase()
2
\
作为延迟评估标记那样灵活。
最佳答案
以我的拙见,我认为您是从错误的 Angular 看待这个问题。如果要手动创建thunk,则需要考虑重构代码。在大多数情况下,重击应该是:
Y = λf.(λx.f (x x)) (λx.f (x x))
function Y(f) {
return (function (x) {
return f(x(x));
}(function (x) {
return f(x(x));
}));
}
x(x)
表达式求值会导致无限循环,最终导致堆栈溢出。因此,在像JavaScript这样的急切语言中,我们改用Z组合器:
Z = λf.(λx.f (λv.((x x) v))) (λx.f (λv.((x x) v)))
function Z(f) {
return (function (x) {
return f(function (v) {
return x(x)(v);
});
}(function (x) {
return f(function (v) {
return x(x)(v);
});
}));
}
x(x)
被渴望的表达式
function (v) { return x(x)(v); }
代替。它包裹在一个大块的东西里。但是,在JavaScript中,编写如下代码的thunk更有意义:
function () {
return x(x).apply(this, arguments);
}
x(x)
评估为一个函数。对于Y组合器,这确实是正确的。但是,如果thunk不求值一个函数,那么我们只返回表达式。
y f = f (y f)
y f
中的
f (y f)
,因此您不会遇到无限循环。在内部,Haskell为每个表达式创建一个thunk。但是,在JavaScript中,您需要显式创建一个thunk:
function y(f) {
return function () {
return f(y(f)).apply(this, arguments);
};
}
repeat
函数。在Haskell中,
repeat
函数定义如下:
repeat :: a -> [a]
repeat x = x : repeat x
repeat
没有边缘情况,它递归地调用自身。如果Haskell不那么懒惰,它将永远递归。如果JavaScript是惰性的,那么我们可以实现
repeat
,如下所示:
function repeat(x) {
return [x, repeat(x)];
}
function repeat(x) {
return function () {
return [x, repeat(x)];
};
}
function evaluate(thunk) {
return typeof thunk === "function" ? thunk() : thunk;
}
evaluate
函数来实现可以将惰性数据结构或严格数据结构作为参数的函数。例如,我们可以使用
take
从Haskell实现
evaluate
函数。在Haskell中,
take
定义如下:
take :: Int -> [a] -> [a]
take 0 _ = []
take _ [] = []
take n (x:xs) = x : take (n - 1) xs
take
来实现
evaluate
,如下所示:
function take(n, list) {
if (n) {
var xxs = evaluate(list);
return xxs.length ? [xxs[0], take(n - 1, xxs[1])] : [];
} else return [];
}
repeat
和
take
:
take(3, repeat('x'));
alert(JSON.stringify(take(3, repeat('x'))));
function take(n, list) {
if (n) {
var xxs = evaluate(list);
return xxs.length ? [xxs[0], take(n - 1, xxs[1])] : [];
} else return [];
}
function evaluate(thunk) {
return typeof thunk === "function" ? thunk() : thunk;
}
function repeat(x) {
return function () {
return [x, repeat(x)];
};
}
function lazy(f) {
return function () {
var g = f, self = this, args = arguments;
return function () {
var data = g.apply(self, args);
return typeof data === "function" ?
data.apply(this, arguments) : data;
};
};
}
lazy
函数,您现在可以如下定义Y组合器和
repeat
:
var y = lazy(function (f) {
return f(y(f));
});
var repeat = lazy(function (x) {
return [x, repeat(x)];
});
var repeat = lazy(function (x) {
return [x, repeat(x)];
});
alert(JSON.stringify(take(3, repeat('x'))));
function take(n, list) {
if (n) {
var xxs = evaluate(list);
return xxs.length ? [xxs[0], take(n - 1, xxs[1])] : [];
} else return [];
}
function evaluate(thunk) {
return typeof thunk === "function" ? thunk() : thunk;
}
function lazy(f) {
return function () {
var g = f, self = this, args = arguments;
return function () {
var data = g.apply(self, args);
return typeof data === "function" ?
data.apply(this, arguments) : data;
};
};
}
lazy
函数。在这种情况下,您可以使用功能组合作为手动创建样式的可行选择。函数组成在Haskell中定义如下:
(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)
function compose(f, g) {
return function (x) {
return f(g(x));
};
}
function compose(f, g) {
return function () {
return f(g.apply(this, arguments));
};
}
slow_foo().toUpperCase()
中,首先执行
slow_foo
函数,然后在其返回值上调用
toUpperCase
方法。因此,我们想以相反的顺序组成函数并将它们链接如下:
Function.prototype.pipe = function (f) {
var g = this;
return function () {
return f(g.apply(this, arguments));
};
};
pipe
方法,我们现在可以组成如下功能:
var toUpperCase = "".toUpperCase;
slow_foo.pipe(toUpperCase);
function () {
return toUpperCase(slow_foo.apply(this, arguments));
}
toUpperCase
函数实际上是一种方法。因此,
slow_foo
返回的值应设置
this
的
toUpperCase
指针。简而言之,我们希望将
slow_foo
的输出通过管道传递到
toUpperCase
中,如下所示:
function () {
return slow_foo.apply(this, arguments).toUpperCase();
}
pipe
方法:
var bind = Function.bind;
var call = Function.call;
var bindable = bind.bind(bind); // bindable(f) === f.bind
var callable = bindable(call); // callable(f) === f.call
callable
方法,我们现在可以如下重构代码:
var toUpperCase = "".toUpperCase;
slow_foo.pipe(callable(toUpperCase));
callable(toUpperCase)
与
toUpperCase.call
等效,因此现在的重击为:
function () {
return toUpperCase.call(slow_foo.apply(this, arguments));
}
var bind = Function.bind;
var call = Function.call;
var bindable = bind.bind(bind); // bindable(f) === f.bind
var callable = bindable(call); // callable(f) === f.call
var someobj = {x: "Quick."};
slow_foo.times_called = 0;
Function.prototype.pipe = function (f) {
var g = this;
return function () {
return f(g.apply(this, arguments));
};
};
function lazyget(obj, key, lazydflt) {
return obj.hasOwnProperty(key) ? obj[key] : evaluate(lazydflt);
}
function slow_foo() {
slow_foo.times_called++;
return "Sorry for keeping you waiting.";
}
function evaluate(thunk) {
return typeof thunk === "function" ? thunk() : thunk;
}
console.log(slow_foo.times_called);
console.log(lazyget(someobj, "x", slow_foo()));
console.log(slow_foo.times_called);
console.log(lazyget(someobj, "x", slow_foo.pipe(callable("".toUpperCase))));
console.log(slow_foo.times_called);
console.log(lazyget(someobj, "y", slow_foo.pipe(callable("".toUpperCase))));
console.log(slow_foo.times_called);
console.log(lazyget(someobj, "y", "slow_foo().toUpperCase()"));
console.log(slow_foo.times_called);
0
Quick.
1
Quick.
1
SORRY FOR KEEPING YOU WAITING.
2
slow_foo().toUpperCase()
2
lazy
的提升函数可以使它们返回thunk,或者使用组合函数来创建新的thunk。
关于javascript - 比function(){return x}更简洁的延迟评估?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18541297/
询问 unrelated question我有这样的代码: public boolean equals(Object obj) { if (this == obj) retur
在我之前的一个问题中 js: Multiple return in Ternary Operator我询问了有关使用三元运算符返回多个参数的问题。但是现在参数IsActveUser boolean(t
假设我有一个带有 return 的 if 语句。从效率的角度来看,我应该使用 if(A > B): return A+1 return A-1 或 if(A > B): return
例如考虑以下代码: int main(int argc,char *argv[]) { int *p,*q; p = (int *)malloc(sizeof(int)*10); q
PyCharm 对这段代码发出警告,说最后一个返回是不可访问的: def foo(): with open(...): return 1 return 0 如果 ope
我想实现这样的目标: 如果在返回 Json 的方法中抛出异常,则返回 new Json(new { success = false, error = "unknown"}); 但如果方法返回 View
它是多余的,但我正在学习 JS,我想知道它是如何工作的。 直接从模块返回函数 let func1 = function () { let test = function () {
我不明白我应该使用什么。我有两页 - intro.jsp(1) 和 booksList.jsp(2)。我为每一页创建了一个 Controller 类。第一页有打开第二页的按钮:
我最近在 Joomla 组件(Kunena,更准确地说是 Kunena)中看到这段代码,那么使用 $this->return VS 简单的 return 语句有什么区别. 我已经用谷歌搜索了代码,但没
我的类实现了 IEnumerable。并且可以编译这两种方式来编写 GetEnumerator 方法: public IEnumerator GetEnumerator() { yield r
我只是在编码,我想到了一个简单的想法(显然是问题),如果我有一个像这样的函数: int fun1(int p){ return(p); } 我有一个这样的函数: int fun1(int p){
这个问题在这里已经有了答案: What does the comma operator do in JavaScript? (5 个答案) 关闭 9 年前。 function makeArray
假设我写了一个 for 循环,它将输出所有数字 1 到 x: x=4 for number in xrange(1,x+1): print number, #Output: 1 2 3 4 现
我最近在这个 Apache Axis tutorial example. 中看到了下面的一段代码 int main() { int status = AXIS2_SUCCESS; ax
function a(){ return{ bb:"a" } } and function a(){ return { bb:"a" } } 这两个代码有什么区别吗,如果有请
function a() { return 1; } function b() { return(1); } 我在 Chrome 的控制台中测试了上面的代码,都返回了 1。 function c()
考虑这三个函数: def my_func1(): print "Hello World" return None def my_func2(): print "Hello World"
这可能是一个愚蠢的问题,但我正在努力,如果有一种简明的方法来测试函数的返回结果,如果它不满足条件,则返回该值(即,传递它)。。现在来回答一个可能的问题,是的,我正在寻找的类似于例外提供的东西。然而,作
我正在测试一个函数,并尝试使用 return 来做什么,并在 PowerShell 5.1 和 PwSh 7.1 中偶然发现了一个奇怪的问题,即 return cmdlet似乎不适合在团体中工作: P
这个问题已经有答案了: Return in generator together with yield (2 个回答) Why can't I use yield with return? (5 个回
我是一名优秀的程序员,十分优秀!