duangsuse::Echo
http://www.yinwang.org/blog-cn/2017/05/25/dsl
不同领域需要的,绝大部分时候只是针对该领域写出的“库代码”,而不是完全不同的“新语言”。分析大部分所谓 DSL,你会发现它们不过提取了通用程序语言里的一部分,比如结构定义,算术表达式,逻辑表达式,条件语句,等等。极少有 DSL 是不能用通用的程序语言构造表示的。绝大部分时候你都可以用一种通用的语言,写出满足领域需求的库代码,然后领域里的人就可以调用库函数来完成他们的任务。这一段王垠说的可以说是废话,那是当然啦,可是也体现了王垠写文章最大的缺点 — 就是他总是喜欢吹毛求疵去批判各种其实 模棱两可 的概念和技术,而且通通是选择其中最差的举例子、只看辣鸡的那一面,而且说了也不提出改进的意见,基本就是一票否决掉,并且建议大家都不要用
这段话改编一下,我是否可以这么说:
不同赛道需要的,绝大部分时候只是针对该赛道组装的“组装车”,而不是完全不同的“新车型”。
分析大部分所谓新型车,你会发现它们不过提取了通用赛车组件里的一部分,比如车轮,ESP,尾翼,载重,等等。
极少有新型车是不能用通用的汽车构造表示的。
绝大部分时候你都可以开一种所有赛道通用的组装车,开出满足竞赛需求的成绩,然后队里的人就可以套用蹩脚的组装来完成他们的任务,无须考虑组织是否妥帖好用。
duangsuse::Echo
http://www.yinwang.org/blog-cn/2017/05/25/dsl
最近去设计的 GalScript 不是一门 DSL,它是定义良好的通用程序设计语言,当然也可以当成 DSL 用,因为它的语法比较灵活,有缩进文法、自定义 prefix, infix, postfix operator,也可以在高阶函数上耍些小把戏,和 Scala 一样,GalScript 也有 implicit arguments(所以 Haskell 的 typeclass 和 instance 其实在 Gal 里都有等价物,虽然 Gal 不支持 parameterized type... Gal 是有虚方法的,这意味着 HM 的 Type class 当然可以实现啊),所以它能够相对比较好的完成 EDSL 的任务
至于 Scheme 系的,也是有很长积累的语言了,我不敢拿它和 Scheme 比
Scheme 的不是不好,但是... 我不知道这个为什么能够拿来吹,Scheme 的宏很强大,但它所基于的概念很简单,甚至不如 Rust 宏(当然我只是从概念的复杂性上讲,虽然两者都能实现,两者语言面向的问题不一样,Rust 复杂一些也是没办法的 核心一样)
比如 Racket 吧,我拿 GeekSpec 举个简单的例子,Racket 里这其实非常简单
Scheme 系可以说是自省(inspect)能力最强的语言了,所以你才能在语言内部定义 AST transform 什么的,当然 Scala 也有 Def macro 就是(实际上现在学术派点的语言都有)
比如我当时设计 GeekSpec 的时候有这么个简单的语法示例
getUsers(limit: Int) -> List of User = /users
抽提一下可以变成这样
我们来定义一个宏,把它搞成这样。个人不是很了解 Racket 的 binding 什么的(迫真,怎么可能,就是有点看不清那个 pattern matching 是干啥子)
为了演示方便,我只定义能够抽提上面那个示例的,整个的语法当然不包括在内(但我个人是反对王垠完全否认 DSL 的态度的,谁说 DSL 不能让解决问题更容易?谁想写一大堆『库函数调用』的冗余代码?)
Scheme 写起来配对括号好淡疼... REPL
至于 Scheme 系的,也是有很长积累的语言了,我不敢拿它和 Scheme 比
Scheme 的不是不好,但是... 我不知道这个为什么能够拿来吹,Scheme 的宏很强大,但它所基于的概念很简单,甚至不如 Rust 宏(当然我只是从概念的复杂性上讲,虽然两者都能实现,两者语言面向的问题不一样,Rust 复杂一些也是没办法的 核心一样)
比如 Racket 吧,我拿 GeekSpec 举个简单的例子,Racket 里这其实非常简单
Scheme 系可以说是自省(inspect)能力最强的语言了,所以你才能在语言内部定义 AST transform 什么的,当然 Scala 也有 Def macro 就是(实际上现在学术派点的语言都有)
比如我当时设计 GeekSpec 的时候有这么个简单的语法示例
getUsers(limit: Int) -> List of User = /users
抽提一下可以变成这样
((GET | POST | PUT | DELETE) '@')? interfName '(' Arg* ')' '->' Ret '=' path
Arg = name ':' typeName
Ret = typeName | typeName 'of' typeName
我们在 Scheme 该怎么定义这种 macro 呢?看看这个(api getUsers (limit: Int) -> List of User = /users)
'("getUsers" (list '(limit Int)) '(of List User) "/users") 怎么样?我们来定义一个宏,把它搞成这样。个人不是很了解 Racket 的 binding 什么的(迫真,怎么可能,就是有点看不清那个 pattern matching 是干啥子)
为了演示方便,我只定义能够抽提上面那个示例的,整个的语法当然不包括在内(但我个人是反对王垠完全否认 DSL 的态度的,谁说 DSL 不能让解决问题更容易?谁想写一大堆『库函数调用』的冗余代码?)
(define (extract-arglist al)好像不 work... 大概,所以算了。
(map (lambda (xx)
(let {[x (symbol->string xx)]}
(let {[lx (string-length x)]}
(if (eq? #\: (string-ref x (- lx 1)))
(string-trim x ":") x)))) al))
(define-syntax api (syntax-rules ()
{ [_ name args _ rett _ url] #'(name (map extract-arglist args) (list just rett) url)
; [_ name args _ retc _ rett _ url] #'(name (map extract-arglist args) '(of retc rett) url)
}))
Scheme 写起来配对括号好淡疼... REPL
duangsuse::Echo
没事,你这是 sublanguage
也不是,因为 GalScript 还是有很多『超集』的语言特性的
sublanguage 因为我 Scheme 不好很浪费时间,Scheme 的特色就是元编程了,不过我基本不用 Scheme...
sublanguage 因为我 Scheme 不好很浪费时间,Scheme 的特色就是元编程了,不过我基本不用 Scheme...
duangsuse::Echo
也不是,因为 GalScript 还是有很多『超集』的语言特性的 sublanguage 因为我 Scheme 不好很浪费时间,Scheme 的特色就是元编程了,不过我基本不用 Scheme...
我直接因为 Scheme 自带函数太少所以不会写 Scheme
伸出手就缺 Common Lisp 里自带的函数,太难受了
伸出手就缺 Common Lisp 里自带的函数,太难受了
duangsuse::Echo
啊,超的部分不是靠内化实现的吗(
不是啊,那只是一种实现方式而已,GalScript 取材于 JavaScript, Ruby, ES6, Scala, Kotlin, C++,但不打算当任何一个的『子集』
你可以看看这个,不过 Gal 的... 我这周可能想办法发一点...
你可以看看这个,不过 Gal 的... 我这周可能想办法发一点...
Telegram
/tmp/duangsuse.sock
实现的难点在学校里已经考虑过了,我觉得是时间问题
难点一方面在解析器上,它是 2D syntax,支持缩进语义所以非常灵活
一方面是在新的 reverse pattern matching 上面,我下了好大功夫设计,而且还很难实现(但是一些基础的 reverse pattern 不难实现)
譬如上面那个 match x + 1 = n 这个,n=1
此时解释实现需构造一个 MixPattern 对象 MixPattern(+1, Unknown("x")) 就可以了,它接受一个输入,然后把输入 -1…
难点一方面在解析器上,它是 2D syntax,支持缩进语义所以非常灵活
一方面是在新的 reverse pattern matching 上面,我下了好大功夫设计,而且还很难实现(但是一些基础的 reverse pattern 不难实现)
譬如上面那个 match x + 1 = n 这个,n=1
此时解释实现需构造一个 MixPattern 对象 MixPattern(+1, Unknown("x")) 就可以了,它接受一个输入,然后把输入 -1…
好,这样就最自由不过了。
啊对了,我看下来,首先是倍感不急了:要这样的话就应该慢慢做,保证质量。
未来可能要考虑 Geekapk 改名。或许可以先看看 Fuchsia OS 的安装包后缀名叫啥了。
啊对了,我看下来,首先是倍感不急了:要这样的话就应该慢慢做,保证质量。
未来可能要考虑 Geekapk 改名。或许可以先看看 Fuchsia OS 的安装包后缀名叫啥了。
duangsuse::Echo
我直接因为 Scheme 自带函数太少所以不会写 Scheme 伸出手就缺 Common Lisp 里自带的函数,太难受了
自带函数不是问题,问题是不会写 Haskell 也不可能会写 Scheme (跑
主要是 Racket 的 pattern matching... 总觉得没有 Haskell 的好用
而且字符串处理什么的 都是要 string->list, list->string 的,如果不会 car/cdr/null? 很麻烦
Racket 还是 R*RS 加了一大堆 cdddr cddaar cdar, ddd 我到没意见,aaa 是什么意思,难不成 head 还能取 N 次?
主要是 Racket 的 pattern matching... 总觉得没有 Haskell 的好用
而且字符串处理什么的 都是要 string->list, list->string 的,如果不会 car/cdr/null? 很麻烦
Racket 还是 R*RS 加了一大堆 cdddr cddaar cdar, ddd 我到没意见,aaa 是什么意思,难不成 head 还能取 N 次?
duangsuse::Echo
我直接因为 Scheme 自带函数太少所以不会写 Scheme 伸出手就缺 Common Lisp 里自带的函数,太难受了
(cons/c any/c (cons/c pair? any/c))你居然是这样的
(x0 : (a : b))
cdaar,受教了。car . car . cdr.... NP毕竟高中没时间啊 GeekSpec 的也有了,就怕你不会写... 不管怎么样好像是必须得有的(因为可以吹,跑)
这周一共设计了三四个,包含 GeekSpec, Tang preprocessor, GalScript, GMarks
这周一共设计了三四个,包含 GeekSpec, Tang preprocessor, GalScript, GMarks
我觉得参考性比较强的案例是 Julia,它想解决现代统计学所用语言的问题。GalScript 应该是想解决普遍化的 C/S 服务的开发吧?
duangsuse::Echo
我觉得参考性比较强的案例是 Julia,它想解决现代统计学所用语言的问题。GalScript 应该是想解决普遍化的 C/S 服务的开发吧?
不对,它唯一的用处是给极安娘当幕后操纵者(也不对,不是唯一的用途
duangsuse::Echo
可以啊,用啥实现~
无所谓,我建议 Java 8 不管怎么样这几周我会断续把 spec 完成(不过下周就放假 8 天...