And it has only one relationship for each input value
即每个在值域内的输入都能得到唯一的输出,它只可能是多对一而不是一对多的关系:
副作用
Wikipedia Side Effect: In computer science, an operation, function or expression is said to have a side effect if it modifies some state variable value(s) outside its local environment, which is to say if it has any observable effect other than its primary effect of returning a value to the invoker of the operation. Example side effects include modifying a non-local variable, modifying a static local variable, modifying a mutable argument passed by reference, performing I/O or calling other functions with side-effects. In the presence of side effects, a program's behaviour may depend on history; that is, the order of evaluation matters. Understanding and debugging a function with side effects requires knowledge about the context and its possible histories.
int sum(int[] array) {
int sum = 0;
for (int i = 0; i < array.length; i++) {
sum += array[i];
}
return sum;
}
尽管大多数语言也会提供 for...in 之类的语法,如 kotlin:
kotlin复制代码
fun sum(array: IntArray): Int {
var sum = 0
for (i in array) {
sum += i
}
return sum
}
但我们注意到,在上面的例子中均引入了两个可变的变量,sum 和 i,站在 sum += i 的视角,它的外部依赖:i 是一个外部的可变状态,因此这个函数并不"纯"。
但另一方面来说,从整体函数对外的视角来看,其还是很"纯"的,因为对于传入的外部 array,始终有唯一的 int 返回值,那么我们追求完全的"纯",完全不使用可变量的目的是什么呢?
在纯函数下要实现完全消灭不可变变量,我们可以这么做:
kotlin复制代码
tailrec fun sum(array: IntArray, current: Int = 0, index: Int = 0): Int {
if (index < 0 || index >= array.size) return current
return sum(array, current + array[index], index + 1)
}
我们编写了退出条件,当 index 在不正常的情况下会,意味着没有东西可以加,直接返回 current,即当前已经算好的值;其余情况则直接返回 current 与当前 index 的值的和,再加上 index + 1 之后所有值的 sum。这个例子已经很简单了,但函数式,递归思维不免会让学传统 OOP 的人需要多加思考一下。
class UserService(private val id: Int) {
fun userToken(password: String): UserToken = TODO()
fun localDb(dbPassword: String): LocalDb = TODO()
}
class ServerService(private val ip: String, private val port: Int) {
fun serverToken(serverSecret: String): ServerToken = TODO()
fun getUser(userToken: UserToken): UserData = TODO()
}
class UserData(
val name: String, val avatarUrl: String, val description: String,
) {
fun uiData(parentLayoutParameters: LayoutParameters): UIData = TODO()
}
Skiplang 的宗旨就在其网站主页,A programming language to skip the things you have already computed,在纯函数的情况下,意味着得知输入状态,那么输出状态就是唯一确定的,这种情况就非常适合做缓存,如果输入值已经计算过,那么直接可以返回缓存的输出值。