动态类型函数式程序设计语言

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'])

待办事项

  • 改进文档
  • 改进解析
  • 支持类型注释

许可证

麻省理工学院许可证

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java需要设置框架。可设置大小(false)以重新绘制()   java我对PDF文件感到困惑   为什么是太阳。jvm。热点。调试器。DebuggerException:无法打开二进制文件`?   设置结果为textview时出现java空指针异常   我应该使用什么同步原语在Java中实现事件驱动程序框架?   java为什么WindowClosing处理程序在退出程序之前不执行后台任务?   如何将“20170712T18:43:04.000Z”转换为安卓或java中的相对时间?   Java,获取按键的时间长度,currentTimeMillies()始终为24   maven构建的java可执行Jar找不到logback。xml   java在其外部的函数中使用for循环中的值   java如何以表格格式将不同长度的数据对齐   java Play 2.5 WebSocket连接构建   maven而非eclipse的java强制转换问题   java如何在JFreeChart中使X轴上的值水平?   构建Java Windows应用程序以访问在线MySQL数据库需要什么   java添加构造函数会出错吗?这没有道理,请帮忙,编程问题   java在一个jframe中的两个JPanel中使用两个绘制方法   java数学或逻辑问题   java如何复制Androids库存摄像头方向更改