本文来自依云's Blog,转载请注明。
突然想给 locate 命令写个 wrapper,把输出中的家目录和一些因加密而引入的软链接显示为~
。自然,这需要读取 locate 命令的输出。在 process 这个库中看到了readProcess
函数,似乎是自己想要的(完整代码):
readLocate :: [String] -> IO String readLocate args = getArgs >>= \cmd -> let args' = args ++ cmd in readProcess "locate" args' ""
结果却发现,原本 locate 命令是边查找边输出的,现在变成了先静默,然后一下子全部吐出来。没有按 Haskell 惯常的「懒惰」脾气来。这样一来,当我发现输出项目太多想按Ctrl-C中断时已经晚了。
Google 了一下,找到这个:
I guess people who want laziness can implement it themselves directly, taking care to get whatever laziness it is that they want.
好吧。我先下回 process 库的源码看看readProcess
为什么不是惰性的:
readProcess :: FilePath -- ^ command to run -> [String] -- ^ any arguments -> String -- ^ standard input -> IO String -- ^ stdout readProcess cmd args input = do (Just inh, Just outh, _, pid) <- createProcess (proc cmd args){ std_in = CreatePipe, std_out = CreatePipe, std_err = Inherit } -- fork off a thread to start consuming the output output <- hGetContents outh outMVar <- newEmptyMVar _ <- forkIO $ C.evaluate (length output) >> putMVar outMVar () -- now write and flush any input when (not (null input)) $ do hPutStr inh input; hFlush inh hClose inh -- done with stdin -- wait on the output takeMVar outMVar hClose outh -- wait on the process ex <- waitForProcess pid case ex of ExitSuccess -> return output ExitFailure r -> ioError (mkIOError OtherError ("readProcess: " ++ cmd ++ ' ':unwords (map show args) ++ " (exit " ++ show r ++ ")") Nothing Nothing)
原来是另开了一 IO 线程读输出,然后等待进程结束后关闭管道。这解释为什么它不是惰性的——它得进程善后处理。
那好吧,改用createProcess
好了:
doLocate :: IO (String, ProcessHandle) doLocate = do argv0 <- getProgName let args = case argv0 of "lre" -> ["-b", "--regex"] _ -> [] args' <- getArgs let args'' = args ++ args' (_, Just out, _, p) <- createProcess (proc "locate" args''){ std_in = Inherit, std_out = CreatePipe, std_err = Inherit } hSetBuffering out LineBuffering (,) <$> hGetContents out <*> return p
改进后的程序,不会等待进程结束,而是返回输出和进程句柄。进程句柄用来等待子进程结束,同时获取退出状态。至于那个管道就不关闭了,留给操作系统解决好了。
main = do (out, p) <- doLocate putStr $ transform out waitForProcess p >>= exitWith
改进版的完整程序在此。
Apr 21, 2012 09:01:44 AM
期待你再改一下 indet/haskell.vim ,
单行 where 缩进两格,下一行缩进两格
do 也是缩进两格
两格 = shiftwidth / 2
像 emacs 的 haskell-mode 那样
f = f
where
f = f
g = do
return f
Apr 21, 2012 03:26:10 PM
我这里的 Emacs haskell-mode 里 where 缩进了四个空格呀。我的 shiftwidth 为 2,刚好和你想要的一样。再除以 2 的话就只剩下一个空格了。而 sw=3 的情况下怎么办呢?
May 03, 2012 10:06:30 PM
催你更新……
{ xx
, yy
} 这个括号会被左移 shiftwidth 格
May 04, 2012 03:36:48 PM
真麻烦啊……你能给我个完整的 Haskell 缩进规则之类的材料吗?
另外,你介意我使用 Python 脚本吗?
May 04, 2012 10:11:30 PM
你有意向改真的太好了……规则看这个就好 http://en.wikibooks.org/wiki/Haskell/Indentation
你的 haskell.vim 已经挺不错了, record 类型很多人喜欢一行一个行首的逗号,都和 { 对齐,而结尾的 } 在你的 haskell.vim 不会和 { 对齐,而是减少了缩进
全世界我就找到你用 haskell 用 vim 有折腾能力愿意分享,python ruby 啥随意,依赖随意,毕竟是靠你提供插件……