我一直在浏览整个网络,寻找关于延续的启示,并且令人难以置信的是,最简单的解释如何能够如此完全混淆像我这样的JavaScript程序员.当大多数文章使用Scheme中的代码解释延续或使用monad时尤其如此.
现在我终于认为我已经理解了延续的本质,我想知道我所知道的是否真的是事实.如果我认为真实的事实并非如此,那么它就是无知而不是启蒙.
所以,这就是我所知道的:
在几乎所有语言中,函数显式地将值(和控制)返回给它们的调用者.例如:
var sum = add(2, 3);
console.log(sum);
function add(x, y) {
return x + y;
}Run Code Online (Sandbox Code Playgroud)
现在,在具有第一类函数的语言中,我们可以将控制和返回值传递给回调,而不是显式返回给调用者:
add(2, 3, function (sum) {
console.log(sum);
});
function add(x, y, cont) {
cont(x + y);
}Run Code Online (Sandbox Code Playgroud)
因此,不是从函数返回值,而是继续使用另一个函数.因此,这个函数被称为第一个的延续.
那么延续和回调之间的区别是什么?
我在这个链接的图像:http://d38daqc8ucuvuv.cloudfront.net/avatars/216/2014-02-19%2017.13.48.jpg
如您所见,这是一个正确方向的正常图像.但是,当我将此链接设置为我的图像标记的src属性时,图像会颠倒.http://jsfiddle.net/7j5xJ/
<img src="http://d38daqc8ucuvuv.cloudfront.net/avatars/216/2014-02-19%2017.13.48.jpg" width="200"/>Run Code Online (Sandbox Code Playgroud)
你知道发生了什么吗?
我已经看到很多函数是根据模式定义的(f .) . g.例如:
countWhere = (length .) . filter
duplicate = (concat .) . replicate
concatMap = (concat .) . map
Run Code Online (Sandbox Code Playgroud)
这是什么意思?
haskell functional-programming pointfree function-composition tacit-programming
我试图了解结果
(*) . (+)
Run Code Online (Sandbox Code Playgroud)
在哈斯克尔.我知道合成算子只是数学函数的标准组成 - 所以
(f . g) = f (g x)
Run Code Online (Sandbox Code Playgroud)
但:
(*) . (+) :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a
Run Code Online (Sandbox Code Playgroud)
我很难理解这种类型的签名.我希望能够做到这样的事情:
((*) . (+)) 1 2 :: Num a => a -> a
= (* (+ 1 2))
Run Code Online (Sandbox Code Playgroud)
的意义是什么 (*) .(+)的签名?我尝试用它来玩它(只是匹配它的签名):
((*) . (+)) 1 (\x -> x + 1) 1
Run Code Online (Sandbox Code Playgroud)
但那无法编译.我正在尝试在编写这些步骤时完成逻辑步骤,但我还没有完全理解它是如何得到这个结果的(以及结果是什么).
我一直在研究依赖类型,我理解以下内容:
?(x:A).B(x)表示"对于所有x类型,A都有类型的值B(x)".因此它表示为其中,当给定一个功能的任何值x类型的A返回类型的值B(x).?(x:A).B(x)表示"存在有x类型A值的类型B(x)".因此,它表示为一对,其第一个元素是类型的特定值x,A其第二个元素是类型的值B(x).旁白:值得注意的是,通用量化总是与物质含义一起使用,而存在量化始终与逻辑联合使用.
无论如何,关于依赖类型的维基百科文章指出:
与从属类型相反的是从属对类型,从属和类型或西格玛类型.它类似于副产品或不相交的联合.
对类型(通常是产品类型)是如何类似于不相交的联合(这是一种和型)?这一直困扰着我.
此外,依赖函数类型如何与产品类型类似?
我知道抽象是关于采取更具体的东西并使其更抽象.这可能是数据结构或过程.例如:
map是对过程的抽象,该过程对值列表执行一组操作以产生全新的值列表.它集中在这样一个事实,即程序遍历列表中的每个项目以生成新列表并忽略对列表中每个项目执行的实际操作.所以我的问题是:抽象与泛化有什么不同?我正在寻找主要与函数式编程相关的答案.但是,如果在面向对象编程中有相似之处,那么我也想了解它们.
oop abstraction functional-programming nomenclature generalization
数学上,函数组合操作是关联的.因此:
f . (g . h) = (f . g) . h
Run Code Online (Sandbox Code Playgroud)
因此,功能组合操作可以被定义为左关联或右关联.
由于Haskell中的正常函数应用(即术语的并置,而不是$操作)在我看来是左联想的,因此函数组合也应该是左联的.毕竟世界上大多数人(包括我自己)习惯于从左到右阅读.
然而,Haskell中的函数组合是正确的关联:
infixr 9 .
Run Code Online (Sandbox Code Playgroud)
我知道函数组合操作是左关联还是右关联并没有什么区别.尽管如此,我很想知道它为什么不留下联想.我想到这个设计决定有两个原因:
$操作类似.除了笑话,在Haskell中,函数组合是否存在正确联想是否有任何有益的理由?如果Haskell中的函数组合是左对联的,它会有什么不同吗?
首先,让我为那些不认识的人定义什么是捷径融合.在JavaScript中考虑以下数组转换:
var a = [1,2,3,4,5].map(square).map(increment);
console.log(a);
function square(x) {
return x * x;
}
function increment(x) {
return x + 1;
}Run Code Online (Sandbox Code Playgroud)
这里我们有一个数组,[1,2,3,4,5]其元素首先被平方,[1,4,9,16,25]然后递增[2,5,10,17,26].因此,虽然我们不需要中间数组[1,4,9,16,25],但我们仍然创建它.
捷径融合是一种优化技术,它可以通过将一些函数调用合并为一个来消除中间数据结构.例如,可以将快捷融合应用于上述代码以产生:
var a = [1,2,3,4,5].map(compose(square, increment));
console.log(a);
function square(x) {
return x * x;
}
function increment(x) {
return x + 1;
}
function compose(g, f) {
return function (x) {
return f(g(x));
};
}Run Code Online (Sandbox Code Playgroud)
如您所见,通过组合和函数将两个单独的map调用融合到一个map调用中.因此,不创建中间阵列.squareincrement
现在,我理解像Immutable.js和Lazy.js这样的库在JavaScript中模仿延迟评估.延迟评估意味着仅在需要时计算结果. …
我正在为一种新的函数式编程语言实现一种类型的系统,我目前正在编写这两种函数来统一它.有两种情况考虑:
+---------+---------+-------------------------------------------------------+
| k1 | k2 | action |
+=========+=========+=======================================================+
| var | var | k1 := k2 ^ k2 := k1 |
+---------+---------+-------------------------------------------------------+
| var | non var | if (!occurs(k1, k2)) k1 := k2 |
+---------+---------+-------------------------------------------------------+
| non var | var | if (!occurs(k2, k1)) k2 := k1 |
+---------+---------+-------------------------------------------------------+
| non var | non var | ensure same name and arity, and unify respective args |
+---------+---------+-------------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)
k1和k2变数然后他们被实例化给对方.k1一个变量时,它被实例化为k2iff …ocaml haskell functional-programming type-inference unification
JavaScript具有词法作用域,这意味着从函数内访问的非局部变量将被解析为定义时该函数的父项范围内存在的变量.这与动态范围形成对比,在动态范围中,从函数内访问的非局部变量在被调用时被解析为该函数的调用范围中存在的变量.
x=1
function g () { echo $x ; x=2 ; }
function f () { local x=3 ; g ; }
f # does this print 1, or 3?
echo $x # does this print 1, or 2?
Run Code Online (Sandbox Code Playgroud)
上面的程序以词法范围的语言打印1然后打印2,并以动态范围的语言打印3然后打印1.由于JavaScript是词法范围的,它将打印1然后2,如下所示:
var print = x => console.log(x);
var x = 1;
function g() {
print(x);
x = 2;
}
function f() {
var x = 3;
g();
}
f(); // prints 1
print(x); // prints 2Run Code Online (Sandbox Code Playgroud)
虽然JavaScript不支持动态范围,但我们可以使用eval以下方法实现它:
var print …Run Code Online (Sandbox Code Playgroud)haskell ×5
javascript ×3
abstraction ×1
agda ×1
callcc ×1
css ×1
curry-howard ×1
eval ×1
html ×1
idris ×1
image ×1
immutable.js ×1
lazy.js ×1
nomenclature ×1
ocaml ×1
oop ×1
pointfree ×1
unification ×1