通过管道将 Haskell 程序连接到 Python 程序
请耐心听我说,因为我对编程还比较陌生。我的基本问题是这样的。我有一个用Haskell写的程序,我想把它的输出(stdout)连接到一个Python程序的输入(stdin)上,这个Python程序会处理和用户界面相关的内容。同样,我也想把Python程序的输出连接到Haskell程序的输入上,这样它就可以把用户点击或输入的信息发送给Haskell程序。
第一个问题是,如果我在这两个程序之间建立了一个管道,假设Python程序的输出已经连接到Haskell程序上,那么如果我用Tkinter创建一些控件,这些控件会在屏幕上显示出来吗?
第二个问题是,我到底该如何建立这个管道?请看下面的示例代码……
main :: IO ()
main = do
-- putStrLn "Enter a number." <- this will be displayed in Python
string <- getLine
putStrLn $ 5 + read string::Int -- or any equivalent function to send to stdout
Python代码大概是这样的。
from Tkinter import *
root = Tk()
label = Label(root, text = "Enter a number.")
label.pack()
enternum = Entry(root)
enternum.pack()
enternum.bind("<Return>", print_num)
-- print_num would essentially be a function to send the Haskell program the number
-- which would be received by the getLine function the way I have it.
如果这个问题之前有人问过,我很抱歉,但还是谢谢你们的帮助!
2 个回答
-2
你也可以通过命令行来建立这个数据处理的流程:
mypython.py | myhaskell.hs
这个Haskell程序会像处理其他标准输入那样进行响应,比如:
myhaskell.hs
1
我使用了Twisted,因为它在轮询方面提供了很好的抽象。简单来说,你需要先定义Python和Haskell程序之间如何沟通的方式(在Twisted中称为协议),比如数据包的长度、如何处理错误等等。然后你只需要把这些代码写出来。
下面是Haskell的代码:
-- File "./Hs.hs"
import Control.Concurrent
import System.IO
main = do
-- Important
hSetBuffering stdout NoBuffering
-- Read a line
line <- getLine
-- parse the line and add one and print it back
putStrLn (show (read line + 1))
-- Emphasize the importance of hSetBuffering :P
threadDelay 10000000
这里是Python的代码:
# File "./pyrun.py"
import os
here = os.path.dirname(os.path.abspath(__file__))
from twisted.internet import tksupport, reactor, protocol
from twisted.protocols.basic import LineReceiver
from Tkinter import Tk, Label, Entry, StringVar
# Protocol to handle the actual communication
class HsProtocol(protocol.ProcessProtocol):
def __init__(self, text):
self.text = text
def connectionMade(self):
# When haskell prog is opened
towrite = self.text + '\n'
# Write a line to the haskell side
self.transport.write(towrite)
def outReceived(self, data):
# When haskell prog write something to the stdout
# Change the label in the tk window to be the received data
label_var.set(data[:-1])
def send_num_to_hs(_event):
content = enternum.get()
# The abspath of the haskell program
prog = os.path.join(here, 'Hs')
reactor.spawnProcess(HsProtocol(content), # communication protocol to use
prog, # path
[prog] # args to the prog
)
# Setting up tk
root = Tk()
# On main window close, stop the tk reactor
root.protocol('WM_DELETE_WINDOW', reactor.stop)
# Since I'm going to change that label..
label_var = StringVar(root, 'Enter a number')
# Label whose content will be changed
label = Label(root, textvariable=label_var)
label.pack()
# Input box
enternum = Entry(root)
enternum.pack()
enternum.bind('<Return>', send_num_to_hs)
# Patch the twisted reactor
tksupport.install(root)
# Start tk's (and twisted's) mainloop
reactor.run()