coffee-js / languages

编程语言学习论坛
https://github.com/coffee-js/languages/issues
112 stars 11 forks source link

基于表和函数解决问题的方案 #67

Open tiye opened 10 years ago

tiye commented 10 years ago

我对编程的理解很大程度上局限在 CoffeeScirpt 操作数据的方式上边. 在 JS 里, 到处可以访问 Object, 生成新的对象, 我更喜欢说是表 (map), 更重要的还有函数, 函数式编程带来了非常灵活的解决问题的方案.

刚开始学习编程语言, 我们会被语言的语法所束缚, 随后还有数据类型的束缚. 渐渐我们发现语法是人们设计的, 数据类型也是设计的, 并且各种语言无法一致. 接着就到了这样的位置, 对问题的理解, 和怎样用代码进行模拟和运算, 是最核心的事情, 而关于语法和数据类型, 我们应当以非常灵活的手段, 很快地调整和演进才对.

我这些年跌跌撞撞明确下来的想法是, 代码就是为了对解决问题的方案进行模拟, 随后是我们怎样保证机器低级的代码, 怎样对我们模拟的方案进行实施.

精彩的例子, 比如说计算 Fibonacci 的函数的例子, 用 CoffeeScript 是这样: 对某个数的计算可以用函数递归计算, 很自然

f = (x) -> if x > 2 then f(x - 1) + f(x - 2) else 1

另一个启发我的例子是对嵌套的括号的解析, 原本我以为当中难以抽象, 然而我找到的方案当中, 代码将每对括号抽象一个函数闭包, 非常巧妙:

(a (b (c (d))))

更大众化的例子是面向对象, 动物有猫有狗, 有继承有方法, 如此等等.

当我思考遇到新的问题是怎样做时, 我想到的大多就是找一个思路, 然后用编程去模拟. 一个明显要做的事情是, 把问题分割成一个个小问题, 然后一个一个将其解决. 于是在代码当中我也想着要找到对代码进行分割的机制, 使得每一部分专注一个问题.

对于分割, 有的通过文件, 有的通过模块打包, 有的通过命名空间, 甚至简单通过表. 然后在更细的层面上, 每个函数的闭包其实也是进行分割, 总之, 我们有很多方案.

但分割的目的不在于隔离, 而是通过抽象屏蔽掉一些复杂度, 让写代码模拟的过程更简单. 实际上我们还是要想尽办法让代码能暴露出来, 一般暴露 API 或者传送数据就好了.

关键的步骤是, 两个处在不同位置的代码, 相互之间需要能交换数据. 比如函数首先相当于保存了一段代码到另一个位置运行, 但除了代码, 执行的上下文也需要传递. 在一个函数当中, 有定义函数的环境的数据, 有从执行环境传入的数据, 这是关键. 我这样说, 是注意到某些情况下, 参与到函数的不会仅仅只有两个作用域的数据, 比如:

A = do ->
  a = 1
  s =
    b: 0
    add: (n) ->
      a += 1
      @b += 1
  s

do B = ->
  A.add 3

这里为了能访问 add 所属的对象, JS 当中使用了 @ 指向对象实例.

A = do ->
  a = 1
  s =
    b: 0
    add: (n) ->
      a += 1
      @b += 1
  s

do B = ->
  s2 =
    add: A.add
  s2.add 3

还有当 add 方法被复制到其他对象上调用时, 可能参与的作用域会更多. 我并没有想清楚具体这里应该怎样处理, 但猜测将会有更多复杂的场景存在. 而那些复杂的场景, 我非常希望编程语言里能很好去模拟.

这同时, 我希望模型能尽量简单, 我不需要记忆大量设计模式才能写出代码. 而是, 希望有一套简单的东西, 借助它, 我能把问题转换然后解决. 现在我想到的, 就是用表和函数(数据结构自然也要), 对各种问题进行好的模拟. 我并没有想清楚, 这些随后将出现在 Cirru 的编写当中.