动态类型函数式程序设计语言
mochi的Python项目详细描述
mochi是一种动态类型的函数式编程语言 节目和演员风格的节目。
它的翻译是用Python3写的。口译员翻译 用mochi编写到python3的ast/字节码的程序。
功能
- 类似python的语法
- 尾部递归优化(仅限自尾部递归),无循环 语法
- 函数定义中不允许重新赋值。
- 基本集合类型是持久数据结构。(使用 耐高温)
- 模式匹配/数据类型,如代数数据类型
- 管道操作员
- 匿名函数定义的语法糖
- actor,就像erlang的actor(使用eventlet)
- 宏,类似于lisp的传统宏
- 内置函数包括itertools模块导出的函数, 配方、功能工具模块和操作员模块
示例
阶乘
deffactorial(n,m):ifn==1:melse:factorial(n-1,n*m)factorial(10000,1)# => 28462596809170545189064132121198688...# Ordeffactorial:n:factorial(n,1)0,acc:accn,acc:factorial(n-1,acc*n)factorial(10000)# => 28462596809170545189064132121198688...
气泡
deffizzbuzz(n):match[n%3,n%5]:[0,0]:"fizzbuzz"[0,_]:"fizz"[_,0]:"buzz"_:nrange(1,31)|>map(fizzbuzz)|>pvector()|>print()
演员
defshow():receive:message:print(message)show()actor=spawn(show)send('foo',actor)actor!'bar'# send('bar', actor)sleep(1)# -> foo# -> bar'foo'!>spawn(show)sleep(1)# -> foo['foo','bar']!&>spawn(show)# The meaning of the above is the same as the meaning of the following.# spawn(show) ! 'foo'# spawn(show) ! 'bar'sleep(1)# -> foo# -> bardefshow_loop():receive:[tag,value]:print(tag,value)show_loop()actor2=spawn(show_loop)actor2!["bar",2000]sleep(1)# -> bar 2000['foo',1000]!>spawn(show_loop)sleep(1)# -> foo 1000[['foo',1000],['bar',2000]]!&>spawn(show_loop)sleep(1)# -> foo 1000# -> bar 2000
分布式计算
# comsumer.mochifrommochi.actor.mailboximportKombuMailbox,ZmqInbox,SQSMailboxdefconsumer():receive:'exit':print('exit!')other:print(other)consumer()kombu_mailbox=KombuMailbox('sqs://<access_key_id>@<secret_access_key>:80//','<queue_name>',dict(region='<region>'))spawn_with_mailbox(consumer,kombu_mailbox)zmq_mailbox=ZmqInbox('tcp://*:9999')spawn_with_mailbox(consumer,zmq_mailbox)sqs_mailbox=SQSMailbox('<queue_name>')spawn_with_mailbox(consumer,sqs_mailbox)wait_all()
# producer.mochifrommochi.actor.mailboximportKombuMailbox,ZmqOutbox,SQSMailboxkombu_mailbox=KombuMailbox('sqs://<access_key_id>@<secret_access_key>:80//','<queue_name>',dict(region='<region>'))kombu_mailbox![1,2,3]kombu_mailbox!'exit'zmq_mailbox=ZmqOutbox('tcp://localhost:9999')zmq_mailbox![4,5,6]zmq_mailbox!'exit'sqs_mailbox=SQSMailbox('<queue_name>')sqs_mailbox![7,8,9]sqs_mailbox!'exit'
烧瓶
fromflaskimportFlaskapp=Flask('demo')@app.route('/')defhello():'Hello World!'app.run()
Rxpy
# usage: mochi -no-mp timer.mochi# original:# https://github.com/ReactiveX/RxPY/blob/master/examples/parallel/timer.pyimportrximportconcurrent.futuresimporttimeseconds=[5,1,2,4,3]defsleep(t):time.sleep(t)returntdefoutput(result):print('%d seconds'%result)withconcurrent.futures.ProcessPoolExecutor(5)asexecutor:rx.Observable.from_(seconds).flat_map((s)->executor.submit(sleep,s)).subscribe(output)# 1 seconds# 2 seconds# 3 seconds# 4 seconds# 5 seconds
回指宏
macroaif(test,true_expr,false_expr):quasi_quote:it=unquote(test)ifit:unquote(true_expr)else:unquote(false_expr)aif([],first(it),"empty")# => "empty"aif([10,20],first(it),"empty")# => 10
要求
- cpython>;=3.2或pypy>;=3.2.1
- rply=0.7.2
- Pyristent=0.10.1
- 路径库=1.0.1
- eventlet=0.17.1
- msgpack python>;=0.4.6
- typeannotations>;=0.1.0
安装
$ pip3 install mochi
$ pip3 install flask Flask-RESTful Pillow RxPY # to run the examples
可选安装
$ pip3 install flask Flask-RESTful Pillow RxPY # to run the examples $ pip3 install pyzmq # to use ZmqInbox and ZmqOutbox $ pip3 install kombu # to use KombuMailbox $ pip3 install boto # to use SQS as transport of KombuMailbox $ pip3 install boto3 # to use SQSMailbox
在pypy上运行mochi时可能会发生以下错误。
ImportError: Importing zmq.backend.cffi failed with version mismatch, 0.8.2 != 0.9.2
在这种情况下,请使用pypy上的pip将cffi的版本更改为0.8.2。
$ pip3 uninstall cffi $ pip3 install cffi==0.8.2
用法
回复
$ mochi >>>
加载并运行文件
$ cat kinako.mochi print('kinako') $ mochi kinako.mochi kinako $ mochi -no-mp kinako.mochi # not apply eventlet's monkey patching kinako
字节编译
$ mochi -c kinako.mochi > kinako.mochic
运行字节编译文件
$ mochi -e kinako.mochic
kinako
$ mochi -e -no-mp kinako.mochic # not apply eventlet's monkey patching
kinako
生成.pyc
$ ls kagami.mochi $ cat kagami.mochi print('kagami') $ mochi >>> import kagami kagami >>> exit() $ ls kagami.mochi kagami.pyc $ python3 kagami.pyc kagami
或
$ mochi -pyc kagami.mochi > kagami.pyc
$ python3 kagami.pyc
kagami
$ mochi -pyc -no-mp kagami.mochi > kagami.pyc # not apply eventlet's monkey patching
$ python3 kagami.pyc
kagami
每个功能的示例
持久数据结构
[1,2,3]# => pvector([1, 2, 3])v(1,2,3)# => pvector([1, 2, 3])vec=[1,2,3]vec2=vec.set(0,8)# => pvector([8, 2, 3]vec# => pvector([1, 2, 3])[x,y,z]=vecx# => 1y# => 2z# => 3get(vec,0)# => 1get(vec,0,2)# => [1, 2]vec[0]# => 1vec[0:2]# => [1, 2]{'x':100,'y':200}# => pmap({'y': 200, 'x': 100})ma={'x':100,'y':200}ma.get('x')# => 100ma.x# => 100ma['x']# => 100ma2=ma.set('x',10000)# => pmap({'y': 200, 'x': 10000})ma# => pmap({'y': 200, 'x': 100})get(ma,'y')# => 200ma['y']# => 200m(x=100,y=200)# => pmap({'y': 200, 'x': 100})s(1,2,3)# => pset([1, 2, 3])b(1,2,3)# => pbag([1, 2, 3])
功能定义
defhoge(x):'hoge'+str(x)hoge(3)# => hoge3
模式匹配
lis=[1,2,3]# Sequence patternmatchlis:[1,2,x]:x_:None# => 3matchlis:[1,&rest]:rest_:None# => pvector([2, 3])foo_map={'foo':'bar'}# Mapping patternmatchfoo_map:{'foo':value}:value_:None# => 'bar'# Type pattern# <name of variable refers to type> <pattern>: <action>match10:intx:'int'floatx:'float'strx:'str'boolx:'bool'_:'other'# => 'int'match[1,2,3]:[1,strx,3]:'str'[1,intx,3]:'int'_:'other'# => 'int'num=union(int,float)vectornums[num]vectorstrs[str]matchnums([1,2,3]):nums[x,y,z]:zstrs[x,y,z]:x# => 3Positive=predicate(->$1>0)Even=predicate(->$1%2==0)EvenAndPositive=predicate(->($1%2==0)and($1>=0))match10:EvenAndPositiven:str(n)+':Even and Positive'Evenn:str(n)+':Even'Positiven:str(n)+':Positive'# => 10:Even and Positive# Or patternmatch['foo',100]:['foo'or'bar',value]:value_:10000# => 100match['foo',100]:[strxorintx,value]:value_:10000# => 100# Record patternrecordPerson(name,age)foo=Person('foo',32)matchfoo:Person('bar',age):'bar:'+str(age)Person('foo',age):'foo:'+str(age)_:None# => 'foo:32'
记录
recordMochirecordAnkoMochi(anko)<MochirecordKinakoMochi(kinako)<Mochianko_mochi=AnkoMochi(anko=3)isinstance(anko_mochi,Mochi)# => Trueisinstance(anko_mochi,AnkoMochi)# => Trueisinstance(anko_mochi,KinakoMochi)# => Falsematchanko_mochi:KinakoMochi(kinako):'kinako '*kinako+' mochi'AnkoMochi(anko):'anko '*anko+'mochi'Mochi(_):'mochi'# => 'anko anko anko mochi'recordPerson(name,age):defshow(self):print(self.name+': '+self.age)foo=Person('foo','32')foo.show()# -> foo: 32# runtime type checkingrecordPoint(x:int,y:int,z:optional(int))Point(1,2,None)# => Point(x=1, y=2, z=None)Point(1,2,3)# => Point(x=1, y=2, z=3)Point(1,None,3)# => TypeError
绑定
x=3000# => 3000[a,b]=[1,2]a# => 1b# => 2[c,&d]=[1,2,3]c# => 1d# => pvector([2, 3])
数据类型,如代数数据类型
dataPoint:Point2D(x,y)Point3D(x,y,z)# The meaning of the above is the same as the meaning of the following.# record Point# record Point2D(x, y) < Point# record Point3D(x, y, z) < Pointp1=Point2D(x=1,y=2)# => Point2D(x=1, y=2)p2=Point2D(3,4)# => Point2D(x=3, y=4)p1.x# => 1
模式匹配函数定义
dataPoint:Point2D(x,y)Point3D(x,y,z)defoffset:Point2D(x1,y1),Point2D(x2,y2):Point2D(x1+x2,y1+y2)Point3D(x1,y1,z1),Point3D(x2,y2,z2):Point3D(x1+x2,y1+y2,z1+z2)_:Noneoffset(Point2D(1,2),Point2D(3,4))# => Point2D(x=4, y=6)offset(Point3D(1,2,3),Point3D(4,5,6))# => Point3D(x=5, y=7, z=9)defshow:intx,message:print('int',x,message)floatx,message:print('float',x,message)_:Noneshow(1.0,'msg')# -> float 1.0 msg# => NoneFileMode=options('r','w','a','r+','w+','a+')defopen_file:strpath,FileModemode:open(path,mode)strpath:open(path,'r')
匿名函数
# Arrow expression.add=(x,y)->x+yadd(1,2)# => 3add=->$1+$2add(1,2)# => 3foo=(x,y)->ifx==0:yelse:xfoo(1,2)# => 1foo(0,2)# => 2pvector(map(->$1*2,[1,2,3]))# => pvector([2, 4, 6])
管道操作员
add=->$1+$22|>add(10)|>add(12)# => 24None|>?add(10)|>?add(12)# => None
惰性序列
deffizzbuzz(n):match[n%3,n%5]:[0,0]:"fizzbuzz"[0,_]:"fizz"[_,0]:"buzz"_:nresult=range(1,31)|>map(fizzbuzz)pvector(result)# => pvector([1, 2, fizz, 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16, 17, 'fizz', 19, 'buzz', 'fizz', 22, 23, 'fizz', 'buzz', 26, 'fizz', 28, 29, 'fizzbuzz'])pvector(result)# => pvector([])pvector(result)# => pvector([])# Iterator -> lazyseqlazy_result=range(1,31)|>map(fizzbuzz)|>lazyseq()pvector(lazy_result)# => pvector([1, 2, fizz, 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16, 17, 'fizz', 19, 'buzz', 'fizz', 22, 23, 'fizz', 'buzz', 26, 'fizz', 28, 29, 'fizzbuzz'])pvector(lazy_result)# => pvector([1, 2, fizz, 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16, 17, 'fizz', 19, 'buzz', 'fizz', 22, 23, 'fizz', 'buzz', 26, 'fizz', 28, 29, 'fizzbuzz'])pvector(lazy_result)# => pvector([1, 2, fizz, 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16, 17, 'fizz', 19, 'buzz', 'fizz', 22, 23, 'fizz', 'buzz', 26, 'fizz', 28, 29, 'fizzbuzz'])
尾随闭包
# The following trailing closure expression is passed to a function as the function’s first argument.result=map([1,2,3])->print($1)$1*2print(doall(result))# -> 1# -> 2# -> 3# => pvector([2, 4, 6])defforeach(closure,seq):doall(filter(closure,seq))# The following trailing closure expression is passed to a function as the function’s first argument.foreach([1,2,3])(item)->new_item=item*100print(new_item)# -> 100# -> 200# -> 300# => pvector([])# Ordefforeach(seq,closure):doall(filter(closure,seq))# The following trailing closure expression is passed to a function as the function’s final argument.foreach([1,2,3])@(item)->new_item=item*100print(new_item)# -> 100# -> 200# -> 300# => pvector([])
关键字参数和dict键的缩写形式
deffoo(a,b,c):a+b+ca=1b=2c=3# This is the same as foo(a=a, b=b, c=c)foo(=a,=b,=c))# => 6# This is the same as {'a': a, 'b': b}{=a,=b}# => pmap({'a': 1, 'b': 2})
宏
macrorest_if_first_is_true(first,&args):matchfirst:quote(True):quasi_quote(v(unquote_splicing(args)))_:quote(False)rest_if_first_is_true(True,1,2,3)# => pvector([1, 2, 3])rest_if_first_is_true("foo",1,2,3)# => Falsemacropipeline(&args):[Symbol('|>')]+argspipeline([1,2,3],map(->$1*2),filter(->$1!=2),pvector())# => pvector([4, 6])
在编译时包含一个文件
$ cat anko.mochi x=10000y=20000
require'anko.mochi'x# => 10000x=30000require'anko.mochi'# include once at compile timex# => 30000
模块
moduleMath:exportadd,subdefadd(x,y):x+ydefsub(x,y):x-yMath.add(1,2)# => 3
$ cat foobar.mochi foo='foo'bar='bar'
require'foobar.mochi'[foo,bar]# => pvector(['foo', 'bar'])foo='foofoofoo'moduleX:exportfoobarrequire'foobar.mochi'deffoobar:[foo,bar]X.foobar()# => pvector(['foo', 'bar'])[foo,bar]# => pvector(['foofoofoo', 'bar'])
待办事项
- 改进文档
- 改进解析
- 支持类型注释
许可证
麻省理工学院许可证