zoukankan      html  css  js  c++  java
  • 一种新的代码组织方式:基于方法而不是基于类聚合代码

    有的情况下,我们更加关注同一方法在不同类中的关系和区别,花费更多时间基于相同的方法比较和查看它们在不同类中的代码。但是由于语言的限制,这些代码散落在程序的不同位置,或者是不同的文件之中,因此很不方便。当我在编写解释器/求值器/编译器时,明显感到了这方面的的不便。当前很少有语言支持这种需求。而coffeescript则在这方面有上佳表现。以下是我写的一个程序,演示了这种想法。

    # 一个求值器,基于后续传递风格的代码(CPS),可以发展成一个支持lisp/函数式风格的语言,具有内置的call/cc, 解析器,和逻辑语言等特性。

    _ = require('underscore') dao = exports class dao.Bindings constructor: (@map = {}) -> clone: () -> new dao.Bindings(_.extend({}, @map)) get:(vari) -> if @map.hasOwnProperty(vari.name) then @map[vari.name] else vari set: (vari, value) -> @map[vari.name] = value; @ deref = (x, env) -> if x instanceof dao.Var then x.deref(env) else x done =(v, solver) -> console.log("succeed!"); result = v.getvalue(solver.env) if result instanceof dao.Atom then result.item else result faildone =(v, solver) -> console.log("fail!"); result = v.getvalue(solver.env) if result instanceof dao.Atom then result.item else result dao.solve = (exp, env = new dao.Bindings(), cont = done, failcont = faildone) -> if _.isNumber(exp) then exp = dao.number(exp) else if _.isString(exp) then exp = dao.string(exp) else if not _.isObject(exp) then exp = dao.atom(exp) else if not exp instanceof dao.Element then exp = dao.atom(exp) new dao.Solver(env, failcont).solve(exp) class dao.Solver constructor: (@env, @failcont, @state) -> clone: (update={}) -> new dao.Solver(update.env or @env.clone(), update.failcont or @failcont, update.state or @state) cont: (exp, cont) -> exp.cont(@, cont or done) solve: (exp, cont) -> cont = @cont(exp, cont or done); cont(dao.NULL, @) class dao.Element class dao.Var extends dao.Element constructor: (@name) -> class dao.Atom extends dao.Element constructor: (@item) -> class dao.Number extends dao.Atom class dao.Print extends dao.Element constructor: (@args...) -> class dao.Succeed extends dao.Element class dao.Fail extends dao.Element class dao.And extends dao.Element constructor: (@x, @y) -> class dao.Or extends dao.Element constructor: (@x, @y) -> class dao.Not extends dao.Element constructor: (@x) -> class dao.Unify extends dao.Element constructor: (@x, @y) -> class dao.Parse extends dao.Element constructor: (@exp, @data) -> class dao.Char extends dao.Element constructor: (@x) -> dao.vari = (name) -> new dao.Var(name) dao.atom = (x) -> new dao.Atom(x) dao.number = (x) -> new dao.Number(x) dao.print_ = (x...) -> new dao.Print(x...) dao.succeed = new dao.Succeed() dao.fail = new dao.Fail() dao.and_ = (x, y) -> new dao.And(x, y) dao.or_ = (x, y) -> new dao.Or(x, y) dao.not_ = (x, y) -> new dao.Not(x) dao.unify = (x, y) -> new dao.Unify(x, y) dao.parse = (exp, data) -> new dao.Parse(exp, data) dao.char = (x) -> new dao.Char(x) dao.Var::toString = "dao.vari(#{@name})" dao.Atom::toString = "dao.atom(#{@item})" dao.Number::toString = "dao.number(#{@item})" dao.Succeed::toString = "dao.succeed" dao.Number::toString = "dao.fail" dao.TRUE = dao.atom(true) dao.FALSE = dao.atom(false) dao.NULL = dao.atom(null) dao.And::toString = "dao.and_(#{@x}, #{@y})" dao.Or::toString = "dao.or_(#{@x}, #{@y})" dao.Not::toString = "dao.not_(#{@x})" dao.Unify::toString = "dao.unify_(#{@x}, #{@y})" dao.Parse::toString = "dao.parse(#{@exp}, #{@data})" dao.Char::toString = "dao.char(#{@x})" dao.Element::deref = (env) -> @ dao.Var::deref = (env) -> env.get(@) dao.Element::getvalue = (env) -> @ dao.Var::getvalue = (env) ->@deref(env) dao.Var::cont = (solver, cont) -> (v, solver) => cont(@.deref(solver.env), solver) dao.Atom::cont = (solver, cont) -> (v, solver) => cont(@, solver) dao.Print::cont = (solver, cont) -> (v, solver) => console.log(@args...); cont(dao.NULL, solver) dao.Succeed::cont = (solver, cont) -> (v, solver) -> cont(dao.FALSE, solver) dao.Fail::cont = (solver, cont) -> (v, solver) -> solver.failcont(dao.FALSE, solver) dao.And::cont = (solver, cont) -> @x.cont(solver, @y.cont(solver, cont)) dao.Or::cont = (solver, cont) -> fc = solver.failcont saved_solver = solver.clone() solver.failcont = (v, solver) => @y.cont(solver, cont)(v, saved_solver) @x.cont(solver, ((v, solver) -> solver.failcont = fc; cont(v, solver))) dao.Not::cont = (solver, cont) -> fc = solver.failcont saved_solver = solver.clone() solver.failcont = cont @x.cont(solver, (v, solver)->fc(v, saved_solver)) dao.Unify::cont = (solver, cont) -> (v, solver) => x = deref(@x, solver.env) y = deref(@y, solver.env) if x instanceof dao.Var solver.env.set(x, y) cont(dao.TRUE, solver) else if y instanceof dao.Var solver.env.set(y, x) cont(dao.TRUE, solver) else if x is y then cont(dao.TRUE, solver) else solver.failcont(dao.FALSE, solver) dao.Parse::cont = (solver, cont) -> (v, solver) => state = solver.state solver.state = [@data, 0] @.exp.cont(solver, ((v, solver) -> solver.state = state; cont(v, solver)))(dao.TRUE, solver) dao.Char::cont = (solver, cont) -> (v, solver) => [data, pos] = solver.state if pos is data.length then return solver.failcont(dao.FALSE, solver) x = deref(@x, solver.env) c = data[pos] if _.isString(x) if x is c then solver.state = [data, pos+1]; cont(dao.TRUE, solver) else solver.failcont(v, solver) else if x instanceof dao.Var solver.env.set(x, c) cont(dao.TRUE, solver) else throw new dao.TypeError(@)
  • 相关阅读:
    Dotnet Core 跨平台GUI 开发实践
    微软的wasm 和 rust的wasm 方案对比
    全栈程序员的新玩具Rust(六)第一个WASM程序
    全栈程序员的新玩具Rust(五)第一个http服务器
    全栈程序员的新玩具Rust(四)第一个图形程序
    全栈程序员的新玩具Rust(三)板条箱
    全栈程序员的新玩具Rust(二)基本代码入门
    mac 上使用 zip 版的mysql
    磁盘 I/O 优化
    Netty WebSocket 开发
  • 原文地址:https://www.cnblogs.com/chaosim/p/3072965.html
Copyright © 2011-2022 走看看