在 Javascript 中是否有任何类似 Haskell 的类型签名的约定
Are there any conventions for Haskell-like type signatures in Javascript
当我最终偶然发现 Hoogle 时,我立即清楚了类型签名的重要性。无需寻找模棱两可和不精确的函数名称,您只需搜索类型签名:
inc :: Number a => a -> a
map :: (a -> b) -> [a] -> [b]
head :: [a] -> a
Hoogle 使代码重用成为第一个 class 事件 :) 因为 Javascript 不是一种纯函数式语言,所以很快就会遇到问题。给出的是这个天真的咖喱实现:
function curry(n, f) {
var args = Array.prototype.slice.call(arguments);
if (typeof n === 'undefined')
args[1] = f.length;
if (n === args.length - 2)
return f.apply(undefined, args.slice(2));
return function() {
return curry.apply(undefined, args.concat(Array.prototype.slice.call(arguments)));
};
}
function add(a, b) { return a + b; }
var addC = curry(2, add);
addC(2)(3); // 5
addC(2, 3); // 5
对应的类型签名会是什么样子?
Number -> ((a1, ..., aN) -> b) -> (a1 -> ... -> aN -> b)
| Number -> ((a1, ..., aN) -> b) -> ((a1, ..., aN) -> b) // ???
这太可怕了,不是想要的结果。在纯函数式语言中,函数总是只有一个参数 - JavaScript 中的任何数字。
Javascript 中的不纯语言特性是否可以用 Haskell 的类型签名系统来表达(我猜它是基于 Hindley-Milner)?是否有针对 javascript 的(标准化)改编?
Are there any conventions how impure language features in Javascript can be expressed with the type signature system of Haskell?
这比您想象的要复杂。举例说明:
function f(a,b) { return a + b; }
最简单的情况下,这是Int -> Int -> Int
。如果你想真正满足 +
对字符串的需求,你需要这样的东西:
Addable a => a -> a -> a
但是嘿! - 你会大喊 - 在 JS 中我们也可以向字符串添加数字! (此时你需要 MultiParamTypeClasses
这是一个 Haskell 扩展)
Addable a b => a -> b -> a
完美。现在我们只需要实现 Addable String String
、Addable Int Int
和 Addable String Int
。看看你需要多少,我们还没有接触到不纯的功能!
当你介绍 this
时,你几乎介绍了 State
。由于每个函数都可以 throw
,因此您也需要 MonadError
。然后他们都有 IO
(console.log
) 可用,对吧?
为此 JS 中几乎每个 函数都需要标记为 RWST IO
,有点违背 monadic 签名的目的。
I got here two years later and thought I could spell out the actual signature this would produce:
Note that Addable
would probably need to be able to add two distinct types to another, third type to fulfill all current JS behaviour. You'd also need to specify R
, W
, and S
.
forall a b c m. (MonadError m, MonadIO m, Addable a b c) => a -> b -> RWST R W S m c
你看,Haskell 足够强大,可以将副作用表示为静态签名。其他语言,如 Idris,也可以这样做,但方式略有不同。然而,它付出了巨大的代价:每个函数现在都被限制为只能执行其签名中的内容。
另一方面,JS 最大的优势之一在于它的动态特性。事实上,您可以非常轻松地编写非常复杂的数据操作:
function f(a) {
console.log(a + this.b);
this.c(function() {
setTimeout(console.log(a), 100);
});
}
是巨大的好处。在 Haskell 中为此写签名会花费很长时间,如果你在五分钟后重写它就没有意义了。
遗憾的是,我认为您所要求的不会很快发生。澄清一下,我严格来说是指像 Haskell 一样强大的类型系统,结合 JS(或 Lua 的弹性和快速原型,我认为它相似但更好)。为了不过分悲观,可插入类型系统正在研究中,希望我们将来会看到更多使用它们的语言。
<opinion>
我看不到任何类似 java 的 JS 插件,包括可怕的 ES6 class
,但在这方面甚至遥不可及。</opinion>
当我最终偶然发现 Hoogle 时,我立即清楚了类型签名的重要性。无需寻找模棱两可和不精确的函数名称,您只需搜索类型签名:
inc :: Number a => a -> a
map :: (a -> b) -> [a] -> [b]
head :: [a] -> a
Hoogle 使代码重用成为第一个 class 事件 :) 因为 Javascript 不是一种纯函数式语言,所以很快就会遇到问题。给出的是这个天真的咖喱实现:
function curry(n, f) {
var args = Array.prototype.slice.call(arguments);
if (typeof n === 'undefined')
args[1] = f.length;
if (n === args.length - 2)
return f.apply(undefined, args.slice(2));
return function() {
return curry.apply(undefined, args.concat(Array.prototype.slice.call(arguments)));
};
}
function add(a, b) { return a + b; }
var addC = curry(2, add);
addC(2)(3); // 5
addC(2, 3); // 5
对应的类型签名会是什么样子?
Number -> ((a1, ..., aN) -> b) -> (a1 -> ... -> aN -> b)
| Number -> ((a1, ..., aN) -> b) -> ((a1, ..., aN) -> b) // ???
这太可怕了,不是想要的结果。在纯函数式语言中,函数总是只有一个参数 - JavaScript 中的任何数字。
Javascript 中的不纯语言特性是否可以用 Haskell 的类型签名系统来表达(我猜它是基于 Hindley-Milner)?是否有针对 javascript 的(标准化)改编?
Are there any conventions how impure language features in Javascript can be expressed with the type signature system of Haskell?
这比您想象的要复杂。举例说明:
function f(a,b) { return a + b; }
最简单的情况下,这是Int -> Int -> Int
。如果你想真正满足 +
对字符串的需求,你需要这样的东西:
Addable a => a -> a -> a
但是嘿! - 你会大喊 - 在 JS 中我们也可以向字符串添加数字! (此时你需要 MultiParamTypeClasses
这是一个 Haskell 扩展)
Addable a b => a -> b -> a
完美。现在我们只需要实现 Addable String String
、Addable Int Int
和 Addable String Int
。看看你需要多少,我们还没有接触到不纯的功能!
当你介绍 this
时,你几乎介绍了 State
。由于每个函数都可以 throw
,因此您也需要 MonadError
。然后他们都有 IO
(console.log
) 可用,对吧?
为此 JS 中几乎每个 函数都需要标记为 RWST IO
,有点违背 monadic 签名的目的。
I got here two years later and thought I could spell out the actual signature this would produce: Note that
Addable
would probably need to be able to add two distinct types to another, third type to fulfill all current JS behaviour. You'd also need to specifyR
,W
, andS
.
forall a b c m. (MonadError m, MonadIO m, Addable a b c) => a -> b -> RWST R W S m c
你看,Haskell 足够强大,可以将副作用表示为静态签名。其他语言,如 Idris,也可以这样做,但方式略有不同。然而,它付出了巨大的代价:每个函数现在都被限制为只能执行其签名中的内容。
另一方面,JS 最大的优势之一在于它的动态特性。事实上,您可以非常轻松地编写非常复杂的数据操作:
function f(a) {
console.log(a + this.b);
this.c(function() {
setTimeout(console.log(a), 100);
});
}
是巨大的好处。在 Haskell 中为此写签名会花费很长时间,如果你在五分钟后重写它就没有意义了。
遗憾的是,我认为您所要求的不会很快发生。澄清一下,我严格来说是指像 Haskell 一样强大的类型系统,结合 JS(或 Lua 的弹性和快速原型,我认为它相似但更好)。为了不过分悲观,可插入类型系统正在研究中,希望我们将来会看到更多使用它们的语言。
<opinion>
我看不到任何类似 java 的 JS 插件,包括可怕的 ES6 class
,但在这方面甚至遥不可及。</opinion>