0

我对 SML 的经验很少。现在我想学习 LiveScript,但我被数据类型困住了。那么,是否可以使用 SML / Haskell / OCaml 等数据构造函数来创建类型?如果不是,创建数据类型的首选方法是什么?

4

1 回答 1

3

Haskell/SML 和 JavaScript/LiveScript/CoffeeScript 之间的主要区别在于:

  • Haskell/SML 是函数式语言,而 JS(大部分)是命令式语言。
  • Haskell/SML 使用严格的静态类型系统,而 JS 使用动态类型系统。
  • Haskell/SML(主要)通过设计防止对变量的副作用。JS没有。

在这些函数式语言中,data类型定义用于编译时类型检查——JS 的动态类型系统在运行时进行类型检查,因此不需要知道对象的确切结构。因此,没有data类型定义的直接翻译。

1. 只使用对象

如果您只想在程序中定义一次性数据结构,只需实例化一个新对象并为其赋予一些属性:

// Create a new object with properties foo and bar
var MyThing = {
    foo: 'a',
    bar: 'b'
};

// Set the baz property of our new object
MyThing.baz = 'c';

// Remove the foo property from our object
delete MyThing.foo;

这在 LiveScript 中几乎是相同的,只是语法较少:

MyThing = { foo: \a, bar: \b }
MyThing.baz = \c
delete MyThing.foo

2. 使用 JS 原型/LiveScript 类

如果您正在处理一个对象的许多实例,或者任何比定义一次性对象更简单的事情,您可能会想要使用对象原型。在 JavaScript 中,所有对象都有一个原型对象作为它们的基础。当你new在构造函数上调用操作符时,你会得到一个函数原型的副本,它被用作this构造函数的上下文。例如:

// Define our constructor
var Thing = function(foo, bar) {
    this.foo = foo;
    this.bar = bar;
};

// Set a 'default' baz property for all Things
Thing.prototype.baz = 'c';

// Create a Thing
var myThing = new Thing('a', 'b');

// Inspect our properties
console.log(myThing.foo, myThing.bar, myThing.baz) // => 'a', 'b', 'c'

这可以直接在 LiveScript 中表示:

# Define a constructor
Thing = (foo, bar) ->
    @foo = foo
    @bar = bar

# Set a 'default' baz property for all Things
Thing::baz = \c

# Create a new Thing
my-thing = new Thing \a \b

# Inspect our properties
console.log myThing.foo, myThing.bar, myThing.baz

或者,更简洁地说,使用class表示(几乎完全)相同事物的语法:

class Thing
    (@foo, @bar) ->
    baz: \c

my-thing = new Thing \a \b

3. 不可变数据结构

如果您来自 Haskell 或 SML,您将熟悉不变性的概念,以及编写无法执行副作用的函数。

在最初的示例中,我们声明了我们的对象 ,myThing然后我们对其进行了变异。在 JS 中,对象通过引用传递给函数,如果不使用调试器,副作用可能会导致难以推断出哪里出了问题。

为了避免这种情况,我们可以使用Immutable.js 库,它提供了不可变的数据结构,例如 Maps(本质上是对象)和 Lists(本质上是数组)。

这是原始示例,使用 Immutable.js 映射重写。

// Create a new Map (like a standard JS object, but immutable)
var myThing = Immutable.Map({ foo: 'a', bar: 'b' });

/*
 * Set the baz property of our new Map
 * Note that the original `myThing` object remains unchanged,
 * because `myThing.set` returns a new Map with the changes supplied to set
 */
var myThingWithBaz = myThing.set('baz', 'c');

var myThingWithBazButNotFoo = myThingWithBaz.delete('foo');
于 2014-05-14T10:20:09.580 回答