有没有办法让TypeScript中的函数仅是纯函数(因此不接受该函数为非纯函数)?如果是的话,哪个?
假设我有这两个F#函数:
let sq x = x*x
let tm = DateTime.Now
Run Code Online (Sandbox Code Playgroud)
显然sq是纯粹的,因为它总是返回给定输入的相同值,而tm是不纯的,因为每次调用它时它将返回不同的值.
通常有一种方法可以确定F#中的特定函数是纯粹还是不纯,而不分析它的作用,换句话说,逐行读取它?
或者是否有一种方法来注释一个函数,告诉编译器在编写函数时该函数是纯函数还是不纯函数?
最后,当调用作为公共语言运行库(如DateTime)一部分的函数时,如何在不尝试的情况下判断它是纯粹的还是不纯的?
注意:"纯"是指维基百科的定义:http://en.wikipedia.org/wiki/Pure_function(permalink)
在计算机编程中,如果关于函数的这两个语句都成立,则函数可以被描述为纯函数:
在给定相同参数值的情况下,该函数始终评估相同的结果值.函数结果值不能依赖于程序执行过程中或程序的不同执行之间可能发生变化的任何隐藏信息或状态,也不依赖于来自I/O设备的任何外部输入.
对结果的评估不会导致任何语义上可观察到的副作用或输出,例如可变对象的突变或输出到I/O设备.
在我们的JavaScript开发团队中,我们采用了redux/react风格编写纯函数代码.但是,我们似乎无法对我们的代码进行单元测试.请考虑以下示例:
function foo(data) {
return process({
value: extractBar(data.prop1),
otherValue: extractBaz(data.prop2.someOtherProp)
});
}
Run Code Online (Sandbox Code Playgroud)
此函数调用取决于对其的调用process,extractBar并且extractBaz每个调用都可以调用其他函数.总之,他们可能需要data构造一个非平凡的模拟 参数来进行测试.
我们是否应该接受制作这样一个模拟对象的必要性,并且实际上在测试中这样做,我们很快发现我们有难以阅读和维护的测试用例.此外,它很可能会导致遍地测试同样的事情,作为单元测试process,extractBar并且extractBaz可能应该也可以写.通过foo接口测试由这些函数实现的每个可能的边缘情况是不实用的.
我们有一些解决方案,但并不真正喜欢任何解决方案,因为它们似乎都不是我们之前看到过的模式.
解决方案1:
function foo(data, deps = defaultDeps) {
return deps.process({
value: deps.extractBar(data.prop1),
otherValue: deps.extractBaz(data.prop2.someOtherProp)
});
}
Run Code Online (Sandbox Code Playgroud)
解决方案2:
function foo(
data,
processImpl = process,
extractBarImpl = extractBar,
extractBazImpl = extractBaz
) {
return process({
value: extractBar(data.prop1),
otherValue: extractBaz(data.prop2.someOtherProp)
});
}
Run Code Online (Sandbox Code Playgroud)
foo当依赖函数调用的数量增加时,解决方案2 非常快速地污染方法签名.
解决方案3:
只需接受这foo是一个复杂的复合操作并将其作为一个整体进行测试的事实.所有缺点都适用.
请提出其他可能性.我想这是一个功能编程社区必须以某种方式解决的问题.
javascript unit-testing functional-programming pure-function
我很喜欢这个pure function概念很简单的例子,比如...
function addTwo(val){
return val + 2;
}
Run Code Online (Sandbox Code Playgroud)
给定相同的参数,它产生相同的结果,导致参考透明度和良好的确定性代码.
但后来我遇到过这样的例子(取自弗里斯比教授大多数指导,但我在其他FP JS书籍上找到了相似的例子)
//pure
var signUp = function(Db, Email, attrs) {
return function() {
var user = saveUser(Db, attrs);
welcomeUser(Email, user);
};
};
var saveUser = function(Db, attrs) {
...
};
var welcomeUser = function(Email, user) {
...
};
Run Code Online (Sandbox Code Playgroud)
我不明白为什么不被认为是外部依赖(因此,不纯)对saveUser或的调用welcomeUser.
我知道从函数/ IO的角度来看,signUp总是返回"相同"(相当的)有线函数,但对我来说这感觉很奇怪.
我很难理解为什么
function multiplyBy(times){
return value => value * times;
}
const fiveTimes = multiplyBy(5);
fiveTimes(10); …Run Code Online (Sandbox Code Playgroud) 在Haskell中打印是一个纯函数; 为什么或者为什么不?我认为这不是因为它并不总是返回与纯函数应该相同的值.
文档说All React组件必须像它们的道具一样充当纯函数. https://facebook.github.io/react/docs/components-and-props.html,但没有解释其背后的真正原因,为什么呢?
纯还原剂没有副作用,并且可以进行时间旅行。它们使对应用程序行为的推理更加容易。
这对我来说很直观。但是我不能说出为什么纯净的还原剂会导致这些积极的非功能性属性。
有人可以帮我阐明为什么减少减速器的副作用使应用程序行为的推理更容易吗?
是因为可以保证运行减速器后状态完全相同吗?
如果是这样,那么即使是副作用(即非纯的)还原剂也肯定可以具有此特性?
GCC 可以使用标志-Wsuggest-attribute=pure和为属性 pure 和属性 const 建议函数-Wsuggest-attribute=const。
在海湾合作委员会的文件说:
许多函数除了返回值外没有任何影响,它们的返回值仅取决于参数和/或全局变量。这样的函数可以像算术运算符一样进行公共子表达式消除和循环优化。这些函数应该用属性 pure 声明。
但是,如果您附加__attribute__((__pure__))到与上述描述不匹配的函数并且确实有副作用,会发生什么?仅仅是因为函数的调用次数可能比您希望的要少,还是有可能产生未定义的行为或其他类型的严重问题?
同样,对于__attribute__((__const__))哪个更严格 - 文档指出:
基本上,这只是比下面的纯属性稍微更严格的类,因为不允许函数读取全局内存。
但是,如果您附加到访问全局内存的函数,实际会发生什么__attribute__((__const__))?
我更喜欢在 GCC / G++ 范围内对实际可能场景进行解释的技术答案,而不是在提到未定义行为时出现的通常的“鼻恶魔”挥手。
我希望能够在 Node 应用程序中安全地执行第三方 javascript。他们提供的代码必须是完全纯净的,这意味着我可以很高兴地将它们与任何全局可用的代码隔离开来。
他们需要调用某些库,但我可以提供一种形式的 require 函数,该函数仅限于提供其他纯函数。除了我给他们的东西之外,他们不需要任何东西。他们应该无法使用任何技巧来访问我包装其函数的闭包之外的任何内容。
有谁知道这是否可能?
我写了一个 UI 元素作为函数组件,它使用 React 的userReducer钩子,它似乎运行没有错误。
useReducer引用了我写的一个函数(想象中称为reducer):
const [state, dispatch] = React.useReducer(reducer, inputData,
(inputData) => initialState(inputData));
Run Code Online (Sandbox Code Playgroud)
有state数据由reducer函数输入和输出;并且有依赖于的“托管”UI 元素state,例如......
return (
<div>
<div>
{state.elements.map(getElement)}
</div>
<ShowHints hints={state.hints} inputValue={state.inputValue} />
</div>
);
Run Code Online (Sandbox Code Playgroud)
...这是正常的。
我担心的是该reducer函数不纯。
副作用是有一个<input>元素的状态由以下之一控制:
const inputRef = React.createRef<HTMLInputElement>();
Run Code Online (Sandbox Code Playgroud)
该<input>控制只是半管理,是这样的:
<input type="text" ref={inputRef} onKeyDown={handleKeyDown} onChange={handleChange}
Run Code Online (Sandbox Code Playgroud)
在onKeyDown和onChange事件是行动派的减速(这是好的),但减速传递的HTMLInputElement实例(即inputRef.current值)作为输入参数,并且该减速套房产HTMLInputElement变异的状态-这是不是<input>幸福一个完全托管的组件,其内容由 reducer 的输出状态定义。
为什么原因<input>元素没有被全面管理的是,我需要控制的选择范围(即start和end …
pure-function ×10
javascript ×5
reactjs ×2
typescript ×2
c ×1
c++ ×1
closures ×1
f# ×1
function ×1
g++ ×1
gcc ×1
haskell ×1
io ×1
io-monad ×1
isolation ×1
monads ×1
react-hooks ×1
redux ×1
sandbox ×1
unit-testing ×1
web ×1