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
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.
/tmp/report
and verify that two lines was appended to /tmp/output
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 the B
call and also one for the A
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.