从Python

时间:2018-04-13 09:17:39

标签: python haskell ghc ghci

我们正在编写一个python程序,试图在给定输入输出对的情况下合成(简单)haskell函数。在整个程序运行过程中,我们生成haskell代码并根据用户提供的示例检查其正确性。 假设我们得到输入“1 2”并且预期输出“3”。我们会(最终) 拿出加号功能。然后我们会跑 在haskell中(\x y -> x + y) 1 2并检查它是否为3。

我们目前的工作方式是运行以下python代码:

from subprocess import Popen, PIPE, STDOUT
proccess = Popen(f'ghc -e "{haskell_code}"', shell=True, stdout=PIPE, stderr=STDOUT) 
haskell_output = proc.stdout.read().decode('utf-8').strip('\n')

由于我们都不熟悉ghc,haskell,进程或与此任何事情有任何关系,我们希望有人可以帮助我们以更高效的方式执行此任务,因为这是目前很慢。

此外,我们希望能够执行多个语句。例如,我们想导入Data.Char,以便我们的函数可以使用“toUpper”。但是,我们目前这样做的方法是发送一个lambda函数和附加的输入,我们不确定如何在上面添加一个import语句(添加“\ n”似乎不起作用)。

总结一下,我们想要最快(运行时)的解决方案,它允许我们从python测试haskell函数(我们没有提前或在某个时间点的所有haskell函数的代码,而是测试因为我们生成代码),同时允许我们使用多个语句(例如,导入)。

道歉,如果任何这些是微不足道或愚蠢的,任何帮助都将受到高度赞赏。

1 个答案:

答案 0 :(得分:3)

这似乎是一件奇怪的事情......但是有趣

这里有两件事情可以立刻想到。首先是使用ghci repl而不是为每次eval尝试生成一个新进程。我们的想法是将您的I / O流式传输到ghci进程,而不是为每次尝试生成一个新的ghc进程。为每个eval启动一个新进程的开销似乎是相当的性能杀手。我通常会去expect,但是既然你想要python,我会打电话给pexpect

import pexpect
import sys
from subprocess import Popen, PIPE, STDOUT
import time


REPL_PS = unicode('Prelude> ')
LOOPS = 100


def time_function(func):
    def decorator(*args, **kwargs):
        ts = time.time()
        func(*args, **kwargs)
        te = time.time()
        print "total time", (te - ts)
    return decorator


@time_function
def repl_loop():
    repl = pexpect.spawnu('ghci')
    repl.expect(REPL_PS)
    for i in range(LOOPS):
        repl.sendline('''(\\x y -> x + y) 1 2''')
        _, haskell_output = repl.readline(), repl.readline()
        repl.expect(REPL_PS)


@time_function
def subproc_loop():
    for i in range(LOOPS):
        proc = Popen('''ghc -e "(\\x y -> x + y) 1 2"''', shell=True, stdout=PIPE, stderr=STDOUT) 
        haskell_output = proc.stdout.read().decode('utf-8').strip('n')
        # print haskell_output


repl_loop()
subproc_loop()

这给了我一个非常一致的>2x速度提升。

有关详细信息,请参阅pexpect doc:https://github.com/pexpect/pexpect/

第二个直接想法是使用一些分布式计算。我没有时间在这里建立完整的演示,但是有很多很好的例子已经存在于互联网和SO的土地上。我们的想法是让多个“python + ghci”进程从公共队列中读取eval attempts,然后将结果推送到公共eval attempt checker。我对ghc(i)知之甚少,但是快速检查显示ghci是一个多线程进程,所以这可能需要多台机器才能启动,每台机器尝试并行尝试不同的子集。

这里可能感兴趣的一些链接:

How to use multiprocessing queue in Python?

https://docs.python.org/2/library/multiprocessing.html

https://eli.thegreenplace.net/2012/01/24/distributed-computing-in-python-with-multiprocessing