https://ice1000.org/lagda/PathToHigherInductiveTypes.html
#PLT #Math #FP .... 赶不上,再说人家现在可能已经到国外留学了,不管怎么说肯定都赶不上吧(
#PLT #Math #FP .... 赶不上,再说人家现在可能已经到国外留学了,不管怎么说肯定都赶不上吧(
Forwarded from duangsuse Throws
plot, imagesc, surface, figure, subplot, hold on/off光会说名词不算什么,能列举出这些才算真‘本事啊... 😶
如果学 CS 的不能像 Morisia 学姐一样说点历史记点年份和语言特性,而只是能满嘴蹦名词而已,要学习何用?
duangsuse::Echo
不过 @drakeet 可能还是能赶上的,加油(开玩笑
This media is not supported in your browser
VIEW IN TELEGRAM
Forwarded from duangsuse Throws
http://agda.github.io/agda-stdlib/Data.Integer.Properties.html#8213 不要以为已经学了很多了... 其实还有很多没学,不看那些还在工程(广度)上的东西吧,这些... 我现在也就是还知道一个 GADT 的 ℕ,而且一些 operator 的 Assoc 都不知道会不会,而且我还不能看透 rewrite 后面那些东西... (就是它是谁的语法糖,因为它这个展开后比较复杂) 再看看效率其实 IJ IDEA 的 Shortcut 和一些基本技巧还会用,也就是比记事本强一点的程度,算了...
duangsuse::Echo
我觉得我是不是应该考虑用正则表达式匹配生成这些无聊的东西了...
琢磨了一下工程量,我觉得『工欲善其事,必先利其器』,因为我手写的好像只有整个的 1/3 左右... 临时溜掉写一个 Kotlin 脚本开小差作弊完成余下部分,顺便复习写 Lexer(跑(绝望
🤔首先考虑我们的『GeekSpec DSL』 语言规范
因为我开始用来制定接口的语言并不规范,我也没有考虑过要拿它生成代码...
算了,那就借此机会,我规范化一下 GeekApk 的 HTTP 接口规范语言... 😐
🤔首先考虑我们的『GeekSpec DSL』 语言规范
readUserTimeline(uid,type,sliceFrom?,sliceTo?) -> array:timeline这是我们『GeekSpec DSL』语言的一些代码范例,都是从我还没有写接口模板的部分复制下来的(逃,因为之前写完的
= timeline/{uid}
readAllTimeline(type,sliceFrom?,sliceTo?) -> array:timeline
= timeline/all
bulkReadUserTimeline(uids,type,sliceFrom?,sliceTo?) -> array:timeline
= timeline/bulk/{uids}
getUserTimelineCount(uid) -> number
= timeline/check/{uid}
getBulkUserTimelineCount(uids) -> number
= timeline/check/{uid}
PUT@updateApp(aid,attr{package,icon,name,screenshots,readme},val) -> [attr,oldVal]
= app/{aid}
因为我开始用来制定接口的语言并不规范,我也没有考虑过要拿它生成代码...
算了,那就借此机会,我规范化一下 GeekApk 的 HTTP 接口规范语言... 😐
duangsuse::Echo
琢磨了一下工程量,我觉得『工欲善其事,必先利其器』,因为我手写的好像只有整个的 1/3 左右... 临时溜掉写一个 Kotlin 脚本开小差作弊完成余下部分,顺便复习写 Lexer(跑(绝望 🤔首先考虑我们的『GeekSpec DSL』 语言规范 readUserTimeline(uid,type,sliceFrom?,sliceTo?) -> array:timeline = timeline/{uid} readAllTimeline(type,sliceFrom?,sliceTo?) ->…
考虑一下我们的『简单形式』代码:
而
首先是我们的『所有规则们』
完美。空格就不用管了。
== EBNF 语法
规定
首字母大写的单词表示一个非终结符(non terminal),反之为终结符(terminal)
语法规则中 Terminal 表示在推导匹配过程中不能继续被子表达式替换的符号,而非终结符反之,可以被替换
(httpMethod '@')? interfaceName '(' Args ')' ('->' ReturnType)? '=' UrlPath
而 Args 形似itself repeatItSelfWithPrefix(','):
name '?'? OptionVals?
而
OptionVals 形似'{' val (',' val)* '}'
而 ReturnType 形似(arrray|object) ':' AtomicObject或者
'[' propertyName (',' propertyName)* ']'
或者AtomicObject而
AtomicObject 形似(ReturnType|number|string|entityName)而
UrlPath 形似prim UrlPath考虑一下我们的 EBNF 范式:
首先是我们的『所有规则们』
AllApiDefs := [ApiDef]考虑一下我们的词法分析器如何识别『注释』(肯定的)
ApiDef :=
-- emmm <- 一个不错的单行注释完美。空格就不用管了。
== EBNF 语法
规定
{} 之中的东西可选,[] 中的东西可以没有或者重复多次(重复 0 次或者多次)首字母大写的单词表示一个非终结符(non terminal),反之为终结符(terminal)
语法规则中 Terminal 表示在推导匹配过程中不能继续被子表达式替换的符号,而非终结符反之,可以被替换
external 的规则则表示我懒̶得̶写̶的东西,自己猜是匹配什么
duangsuse::Echo
考虑一下我们的『简单形式』代码: (httpMethod '@')? interfaceName '(' Args ')' ('->' ReturnType)? '=' UrlPath 而 Args 形似 itself repeatItSelfWithPrefix(','): name '?'? OptionVals? 而 OptionVals 形似 '{' val (',' val)* '}' 而 ReturnType 形似 (arrray|object) ':' AtomicObject…
总结一个 PEG 文法:
好了,那么修改完上面两个,就能拯救 GeekApk 目前 API 文档的烂摊子... 😕
File := Interface*
Interface :=
(httpMethod '@')? interfaceName '(' Arg* ')' ('->' ReturnType)?
'=' urlPath
Arg := argName '?'? OptionVals? (',' Args?)
OptionVals := '{' possibleValue (',' possibleValue)* '}'
ReturnType
:= (array|object) ':' Atom
| '[' propertyName (',' propertyName) ']'
| Atom
Atom := (ReturnType|number|string|entityName)
... 等等,我们还没有支持这些语法(其实目标是拿来生成 Boilerplate code 的,不过要这些也有用)index() -> object<category,object<operation,linkTemplate>>====
version() -> plain
upTime() -> (string|number):datetime上面两个还是不要支持,要支持在 Kotlin 项目上可能也没有多大价值
detailedInfo() -> object:<prop,desc>
PUT@transferAppOwner(aid,uid) -> object:[aid,old,new]这两个是自己有问题,也不支持
DELETE@deleteAppUpdate(aid,rev) -> object:appUpdate
listMetaUser(sort?{created,followers},sliceFrom?,sliceTo?) -> array:object:user
这个也是好了,那么修改完上面两个,就能拯救 GeekApk 目前 API 文档的烂摊子... 😕
GeekSpec := ApiSpec*
ApiSpec :=
(httpMethod '@')? interfaceName '(' Arg* ')'
('->' (ReturnType|Dict))? '=' urlPath
Arg := argName '?'? OptionVals? (',' Arg?)
OptionVals := '{' possibleValue (',' possibleValue)* '}'
ReturnType
:= (array|object) ':' Atom | Atom
Atom := (boolean|number|string|datetime|plain|entityName|)
Dict := '[' DictItem (',' DictItem)* ']'
DictItem
:= ReturnType
| '$' fieldName ':' ReturnType
https://pegjs.org/online
的编辑器没有自动保存,我写了半天的内容全丢了。
真棒。
一方面有我自己没有理清递归思路,还有莫名其妙使用递归解析规则的原因,我开始根本没想到自己应该在写逻辑的时候好好想想这是递归的解析规则
另一方面,PEG.js 自己就有问题,我绑定给它的参数它有时候都弄不正确,? 语义根本行为莫名其妙,真是令人琢磨不透,害得我查了半天还找不到解决方案,最后自己勉强弄了一个能用的 workaround
ApiSpec :=
(httpMethod '@')? interfaceName '(' Arg* ')'
('->' (ReturnType|Dict))? '=' urlPath
Arg := argName '?'? OptionVals? (',' Arg?)
OptionVals := '{' possibleValue (',' possibleValue)* '}'
ReturnType
:= (array|object) ':' Atom | Atom
Atom := (boolean|number|string|datetime|plain|entityName|)
Dict := '[' DictItem (',' DictItem)* ']'
DictItem
:= ReturnType
| '$' fieldName ':' ReturnType
https://pegjs.org/online
的编辑器没有自动保存,我写了半天的内容全丢了。
真棒。
一方面有我自己没有理清递归思路,还有莫名其妙使用递归解析规则的原因,我开始根本没想到自己应该在写逻辑的时候好好想想这是递归的解析规则
另一方面,PEG.js 自己就有问题,我绑定给它的参数它有时候都弄不正确,? 语义根本行为莫名其妙,真是令人琢磨不透,害得我查了半天还找不到解决方案,最后自己勉强弄了一个能用的 workaround
pegjs.org
Online Version » PEG.js – Parser Generator for JavaScript
PEG.js is a parser generator for JavaScript based on the parsing expression grammar formalism.
duangsuse::Echo
GeekSpec := ApiSpec* ApiSpec := (httpMethod '@')? interfaceName '(' Arg* ')' ('->' (ReturnType|Dict))? '=' urlPath Arg := argName '?'? OptionVals? (',' Arg?) OptionVals := '{' possibleValue (',' possibleValue)* '}' ReturnType := (array|object) ':'…
递归的规则能不要写就不要写
上面那个
Args := argName '?'? OptionVals? (',' Args)?
就应该写成 Repeat 组合子的形式,一上来就递归很难受,免得麻烦,要知道 PEG.js 那个鸡肋破真参数绑定工作下,即使好好分析了也未必能做到解决问题... 难受的很
上面那个
Args := argName '?'? OptionVals? (',' Args)?
就应该写成 Repeat 组合子的形式,一上来就递归很难受,免得麻烦,要知道 PEG.js 那个鸡肋破真参数绑定工作下,即使好好分析了也未必能做到解决问题... 难受的很
{
let filterIsNotArray = (xs => xs.filter(x => !Array.isArray(x)));
let isNotUndef = (s => s != 'undefined');
let head = xs => xs[0]
}
GeekSpec = specs:(_ ApiSpec _)* { return specs.map(x => head(filterIsNotArray(x))); }
entityName = letter+
interfaceName = letter+
urlPath "url letters" = (letter / [:/.{}?&=%])+
argName = letter+
possibleValue = letter+
fieldName = letter+
httpMethod
= "GET" / "POST"
/ "PUT" / "DELETE"
/ "PATCH" / "OPTIONS"
/ "HEAD"
ApiSpec =
name:interfaceName _ '(' _ a:Arg? as:(_ "," _ Arg)* _ ')'
_ rtxd:('->' _ (ReturnType / Dict))? _ '=' _ url:urlPath {
return {
method: "GET",
name: name.join(''),
args: a == null ? [] : [a].concat(as.map(ra => ra[3])),
return : isNotUndef(typeof rtxd) ? (rtxd == null ? null : rtxd[2]) : null,
url: url.join('')
};
}
/
method:httpMethod '@' name:interfaceName _ '(' _ a:Arg? as:(_ "," _ Arg)* _ ')'
_ rtxd:('->' _ (ReturnType / Dict))? _ '=' _ url:urlPath {
return {
method: method,
name: name.join(''),
args: a == null ? [] : [a].concat(as.map(ra => ra[3])),
return : isNotUndef(typeof rtxd) ? rtxd[2] : null,
url: url.join('')
};
}
Arg = name:argName _ q:('?' / "!"?) _ ov:OptionVals? {
return {
name: name.join(''),
required: q != "?",
options: ov
};
}
OptionVals = '{' _ pv:possibleValue? pvs:(_ ',' _ possibleValue)* _ '}' {
return pv == null ? [] : [pv.join('')].concat(pvs.map(rpv => rpv[3].join('')));
}
ReturnType
= axo:("array" / "object") ':' a:Atom { return { type: axo, of: ((typeof a != 'string') ? a.join('') : a) }; }
Atom = "boolean" / "number"
/ "string" / "datetime"
/ "plain" / entityName
Dict = '[' _ di:DictItem? dis:(_ ',' _ DictItem)* _ ']' {
return di == null ? [] : [di].concat(dis.map(rd => rd[3]))
}
DictItem
= ReturnType
/ '$' name:fieldName ':' rt:ReturnType {
return { name: name.join(''), type: rt };
}
_ "whitespace"
= [ \t\n\r]*
letter "letter"
= [A-Za-z0-9_\-]
大功告成(其实一点都不,而且某非常智障的 duangsuse 没有用到递归(因为这个玩意开始的时候我输入的数据比较多,分析起来当场爆炸留下心理阴影,列表处理方法我又到处乱用 e.g. splice, reverse, concat 却没有想到 map...),非常不爽) #Parser #PL管他呢反之先火速处理(
duangsuse::Echo
{ let filterIsNotArray = (xs => xs.filter(x => !Array.isArray(x))); let isNotUndef = (s => s != 'undefined'); let head = xs => xs[0] } GeekSpec = specs:(_ ApiSpec _)* { return specs.map(x => head(filterIsNotArray(x))); } entityName = letter+ interfaceName…
This media is not supported in your browser
VIEW IN TELEGRAM
duangsuse::Echo
{ let filterIsNotArray = (xs => xs.filter(x => !Array.isArray(x))); let isNotUndef = (s => s != 'undefined'); let head = xs => xs[0] } GeekSpec = specs:(_ ApiSpec _)* { return specs.map(x => head(filterIsNotArray(x))); } entityName = letter+ interfaceName…
简单点来说,GeekSpec DSL 使用类似如下语法:
GET@methodName(args) = urlTemplate
如果 使用的 HTTP 动词是 GET,那 GET@ 可以省掉不写
args:
argName! argName?
如果不写 ? 或者 !,默认 ?(可选参数)
后面还可以跟 {} 包含参数值选项
返回值:符合 JSON 规范,开头必须是 object: 或者 array:,不支持递归类型(比如 array:array:string)
后面可以跟 boolean/number/string/datetime/plain/entityName(随便什么其他的东西)
返回值也可以是 Dict:
[]
dict 组织一打不同的返回值,其实是 object(不关心属性名),可以为他们命名
[$name:type]
GET@methodName(args) = urlTemplate
如果 使用的 HTTP 动词是 GET,那 GET@ 可以省掉不写
args:
argName! argName?
如果不写 ? 或者 !,默认 ?(可选参数)
后面还可以跟 {} 包含参数值选项
返回值:符合 JSON 规范,开头必须是 object: 或者 array:,不支持递归类型(比如 array:array:string)
后面可以跟 boolean/number/string/datetime/plain/entityName(随便什么其他的东西)
返回值也可以是 Dict:
[]
dict 组织一打不同的返回值,其实是 object(不关心属性名),可以为他们命名
[$name:type]
duangsuse::Echo
geekspec_parser.js
GeekApk 的 v1b API 规范正在使用 GeekSpec DSL 语言重写
duangsuse::Echo
好像能用
目前勉强能用的 GeekSpec DSL 将能够解决不断手工重复代码的问题,起码可以大大提升以后的接口开发效率
当然你也可以喷我不上 RESTful 所以才有这些鬼事情,不过我觉得没什么。
当然你也可以喷我不上 RESTful 所以才有这些鬼事情,不过我觉得没什么。