【问题标题】:Generating and running Haskell code from Python从 Python 生成和运行 Haskell 代码
【发布时间】:2018-04-13 18:14:04
【问题描述】:

我们正在编写一个 python 程序,它试图在给定输入-输出对的情况下合成一个(简单的)haskell 函数。在程序的整个运行过程中,我们生成haskell 代码并根据用户提供的示例检查其正确性。 假设我们得到输入“1 2”和预期输出“3”。我们会(最终) 想出加号功能。然后我们会运行 (\x y -> x + y) 1 2 在 haskell 中并检查其计算结果是否为 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 函数和附加到它的输入,我们不确定如何在其上方添加导入语句(添加“\n”似乎不起作用)。

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

抱歉,如果其中任何一个琐碎或愚蠢,任何帮助将不胜感激。

【问题讨论】:

  • IIRC ghc -e 非常受限。您也许可以只使用完全限定的Data.Char.toUpper,或者编写一个完整的文件并使用runghc 它。
  • 使用 Data.Char.toUpper 似乎解决了第二个问题。但是,这将要求我们使用完全限定的名称,而不是简单的“toUpper”。使用 runghc 会与 ghc -e 一样快还是更快?感谢您的快速回复!

标签: python haskell ghc ghci


【解决方案1】:

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

这里立刻想到了两件事。首先是使用 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 文档了解更多信息: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

【讨论】:

    猜你喜欢
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多