Skip to content
Zoom.Quiet edited this page Mar 29, 2011 · 4 revisions

强译! http://yuheng.randoms.us/blog/2010/10/solo-notes/

SOLO 笔记

介绍

  • 代码: http://github.com/kuangyh/solo
  • 表达式 Expressive
    • Python 是表达式的
    • Python 但是不彻底的
    • 相比 LISP
    • 以及进行数据结构操纵时
  • FP
    • Python 不是函式语言,但是 我要!
    • Python 有那么一点儿 FP 特性
  • 目标
    • 将FP 特性引入Python ,并 Pythonic 化
    • 整得更加表达式化
    • 写少作多 Write less, do more
  • SOLO 库
    • 为了数据
    • 匹配: 模式的
    • 操纵: 处理是管道化的,数据模板的

更多的神器

所罗门

https://github.com/kuangyh/solomon

  • 啥也不说了,这是基于Py 的彻底面向风格化的 SDL 了!

设计

宏观上: 查询 OVERALL: QUERY

查询描述序列应用成对象

q = Query()

# 获取键的 ``值``, 调用其超类方法
q = q['value'].upper()

# ``编译`` 成一个调用
compiled = ~q

compiled({'value' : 'hello'})  # => 'HELLO'

得到 Q = Query() 就可以认为,``Q`` 是个数据库输入的 魔法占位符

串接 CHAIN

本质上,查询都是描述为一系列指令, 指令可以是方法调用和函式(接受一个参数)

查询使用常规语法来调用,如前述使用 + 和函式接合

方法调用

同前设计

函式 FUNCTION

传统的 函式化 结合, 查询使用 + 来整合入

q = P['value'] + (lambda x: x * 2)
(~q)({'value' : 'hello'})    # => 'hellohello'

数据模板 DATA TEMPLATE

在 Python 我们可以:

value = {
  'name' : foo(bar(value['x'])),
  'ooxx' : [
     'example' : 123,
     'ls' : map(lambda x: x * 2, value['values'])
  ]
}

当我们查询时,想这么写:

Query() + (lambda value: { 'name' : foo(bar(value ... } )

很囧,特别是我们想在 查询内部使用 lambda 时,所以,我们想要

Q = Query()

Q + {
  'name' : Q['x'] + bar + foo
  'ooxx' : [
    'example' : 123,
    'ls' : Q + Map(lambda x: x * 2)
  ]
}

如果实现这种形式,就称 数据模板. 查询内置一个编译器,根据数据模板,编译成可执行的函式,最后输出整个数据结构体.

在这种强大的数据模板基础上,我们就可以这么写:

q = Q[Q['key']].join(Q['list'])
(~q)({'key' : 'delim', 'delim', ':', 'list' : ['foo','bar']})
# => 'foo:bar'

因为 __getitem__ 返回的键, 可视作数据模板方法调用时的参数列表, 能对输入进行评估,并``真正``应用到数据的方法调用上.

模式匹配

模式匹配 是一组处理器, 检验输入是否匹配特定的参数模式,如果有匹配,执行对应的并返回; 否则抛出异常.

Erlang

杀手特性

这就是著名的 Erlang 的内置特性哪,通过同名函式参数的不同来高效匹配同一接口的不同事务!

单值匹配

Q + Value(const_value)
Q + Type(int)
Q + Test(true_or_flase_function)

结构匹配

注意: 结构匹配 不返回输入本身,某种程度上这很难解释 ;-(

Q + Seq([first_pat, second_pat...])
Q + Tuple([first_pat, secon_pat..])
Q + Mapping({'key' : pat ...})

模式匹配模板

我们也能象数据模板那样进行模式的模板操作

# it matches a list/tuple that has 3 elements,
# the first is 'send', the second is a string and the third is a
# mapping that has a ``value'' element larger than 0
Q / ( 'send', str, { 'value' : Q/int/(lambda x: x > 0) } )
# 这里匹配 3元素的 list/tuple
# 第一个元素得是 'send', 第二个是个字串
# 第三个须是 键``value`` 对应的值>0 的字典

模板编译器,将编译一系列组合进行匹配处理.

提取器 EXTRACTOR

匹配复杂对象时,我们可以使用各种提取器,转换成简单的结构(列表,字典), 再进行模式匹配

# When match, Regex processor will return (groups, groupdict)
# Then we can match the groups, bind values, convert value etc.
q = (Q + extract.Regex(r'([^\s]+)\s+([^\s]+)') + Q[0]) / ( I.cmd, (Q + int) / I.value )
# 当完成正则匹配后,将返回 (groups, groupdict)
# 然后我们就可以进一步匹配 groups, bind values, convert value etc.

ctx = makectx()
(~q)('send 1', ctx)
ctx  # => { 'cmd' : 'send', 'value' : 1 }

吐糟

形式化语言

创造出各种节省输入的形式化关键词,这是 Perl 的范儿哪...

背景 CONTEXT

在 Python 中我们能

name, value = ('key', 123)

这就是一种模式匹配(匹配到2元素元组) 以及名称约束.我们无法在查询本身这么作.

在这一背景中,上下文是个字典, 但是借助局部和全局线程,以及 with 语法,我们可以:

def foo():
   currctx()['value'] = 10

ctx = makectx()
with ctx:
   ...
   foo()
   ctx['value']       # => 10

注意: with ctx 是可堆叠的,我们在每个线程都要维持这一全局堆栈.

结合语法糖 (魔力的``I``),我们得到

# exchange 2 elements of the list
q = Q / (I.x, I.y) + [I.y, I.x]

ctx = makectx()
with ctx:
    (~q)([1,2])  # => [2,1]
ctx => {'x' : 1, 'y' : 2}

I.name 将输入的值丢到上下文中来匹配环境, 进而从正常指令和数据模板中获得返回值;

控制流程

基于查询的函式设计,我们可以轻易的实现各种流程控制,例如选择.

这一灵感来自Scala语言的设计.

# a shortcut for Q + Choice([Q/in, Q/str + int])
Q | ( Q/int, Q/str + int)
Implementation.

class Choice(object):
    def __init__(self, *checks):
        self.checks = map(query.Q.__add__, checks)
        self.checks_call = map(lambda x: ~x, self.checks)

    def __call__(self, value):
        last_error = None
        for check in self.checks_call:
            try:
                return check(value)
            except BaseException, e:
                last_error = e
        if last_error is not None:
            raise last_error
        else:
            return value

批处理

批量处理系统的目标是 LINQ. 即:提供一个表达方式来描述内存中的数据结构和数据关系, 就象关系型数据库.

目前我们只实现地图和过滤,并提供对应的 语法糖

# Q + Filter(Q / int)
Q // int
# Q + Map(Q + { 'name ...
Q >> { 'name' : Q[0], 'value' : Q[1] }

实施

编译器将查询它编译成Python的代码. 我们努力使生成的Python代码尽可能高效.

事实上我们正在定义一种新的语言,使用Python语言构建组件,嵌入Python并保持 Pythonic!

例子

数据模板

数据源

[ { 'title' : '...'
    , 'username' : '...' }
]

要转换成 atom 聚合源(类似 JSON, GData JSON 定义)

atomfeed = Q + {
    'title' : { '$t' : 'Atom feed'},
    'entry' : Q >> {
        'title' : { '$t' : Q['title'] },
        'link' : {
            'href' : I['http://mail.qq.com/mail/{0}.html'.format](Q['id']),
            'rel' : 'alternative'
            },
        'author' : {
            'name' : Q['username'].capitalize()
            'email' : I['{0}@mail.qq.com'.format](Q['username'])
            }
        }
    }

真实的应用

WEB 应用
  • Request routing (matching, fetch input params, and route, with Choice)
  • Form validation and processing
  • Data source validation
  • Various data model mapping