问题
Ok, so some time ago I was thinking of basing the effect of a keybinding in my xmonad based on the output of a script on my box. I eventually decided not to do that for unrelated reasons but I did recently try to do something similar just as an exercise in learning Haskell.
So, given the function:
test = readProcess "echo" ["-n", "gvim"] []
This throws up because test returns IO String and spawn expects a String.
((modm, xK_y), spawn ("xmessage " ++ test))
Ok. That's cool. I get it that IO operations are unpredictable and so they should be kept separate. Fine. So I did some poking around online and got to this (dropped the xmessage and just want to pass the output of test by itself):
((modm, xK_y), liftIO test >>= spawn)
This is worse. It annoyingly compiles but nothing happens when I try out the binding. (I also replaced it with just spawn "xmessage test" and that worked)
So, then I thought "Maybe there's something wrong with my function" so I repl it but from GCHi I get "gvim" which is correct. So then I write it to a haskell file:
main = test >>= putStrLn
test = readProcess "echo" ["-n", "gvim"] []
Also works correctly.
So, where did I go wrong?
EDIT: Solution was to use runProcessWithInput
instead of readProcess
.
Related link: https://ghc.haskell.org/trac/ghc/ticket/5212 xmonad io binding not working
回答1:
Update
Apparently the solution (see the comments below) is to use readProcessWithInput
Original Answer
You said that:
liftIO test >>= spawn
didn't work, but how about:
liftIO test >>= (\m -> spawn ("xmessage " ++ m))
Also note that the string returned by readProcess
likely will have a newline at the end, and that may be affecting things.
Some more things to try in this vein:
return "gvim" >>= (\m -> spawn ("xmessage " ++ m))
import Data.Char
do { m <- liftIO test; spawn ("xmessage " ++ (filter isAlpha m)) }
The first one should succeed since it is equivalent to spawn "xmessage grim"
. The second one will strip any newlines (indeed, any non-letters) from the output of test
.
Some further things which might shed light on what is going on:
Create a script called
/tmp/report
with these contents:#!/bin/sh ( date; echo "/tmp/report was called with args" "$@") >> /tmp/output
Make
/tmp/report
executable.- Run
/tmp/report
and verify that two lines was appended to/tmp/output
- In your monad config, make the action
spawn "/tmp/report A"
. Test the action by seeing if the expected line is appended to/tmp/output
. Try making the monad action this:
liftIO (readProcess "/tmp/report" ["B"] "") >> spawn "/tmp/report A"
(Note we are using
>>
here, not>>=
.) When you trigger the action you should see a report line for theB
call and also one for theA
call.
Based on what you see in the file /tmp/output
you should be able to determine whether the readProcess
command is even being executed as well as the spawn
command is triggering.
来源:https://stackoverflow.com/questions/37174160/how-do-i-use-the-output-of-readprocess-in-an-xmonad-keybinding