patternMinor
Haskell program to turn off computer
Viewed 0 times
turnprogramcomputerhaskelloff
Problem
This a program I wrote to execute various power-related function on my computer. It accepts one command-line argument that describes what action to take and then performs that action. Usage looks like this:
Here's the code. Any feedback whatsoever is appreciated, regarding either my program's design or the style, formatting and good/bad practices of my code.
```
--power.hs
import System.Cmd(system)
import System.Environment(getArgs)
type Arg = String --A command-line argument
type Cmd = String --A command to execute
--paths to programs that will carry out the actions
shutdown_path = "C:\\Windows\\System32\\shutdown.exe"
rundll32_path = "C:\\Windows\\System32\\rundll32.exe"
--assoc list mapping arguments to the action that should be taken when that argument is received
cmds :: [(Arg, Cmd)]
cmds = [ ("shutdown", shutdown_path ++ " /s /t 0" ),
("sleep", rundll32_path ++ " powrprof.dll,SetSuspendState 0,1,0"),
("hibernate", shutdown_path ++ " /h" ), -- does not work
("lock", rundll32_path ++ " user32.dll,LockWorkStation" ),
("restart", shutdown_path ++ " -t 0 -r -f" ) ]
--gets the argument passed to the program. Calls error if there is not exactly one argument.
extractCmdOrFail :: IO Arg
extractCmdOrFail = getArgs >>= check
where check [s] = return s
check _ = error "Wrong Number of arguments"
--finds the command to execute from the given command-line arg. Calls error if no command is found.
findCmdOrFail :: Arg -> Cmd
findCmdOrFail s = check $ lookup s cmds
where check (Just s') = s'
check Nothing = error "Unknown command: " ++ s
--prompts the user to confirm whether or not they want to execute the command.
prompt :: Cmd -> Arg -> IO ()
prompt cmd name = putStr ("Execute " ++ name ++ "? (y/n)\n") >>
C:\Users\Noah\My Code\GHCI> power sleep
execute sleep? (y/n)
y
//computer goes to sleepHere's the code. Any feedback whatsoever is appreciated, regarding either my program's design or the style, formatting and good/bad practices of my code.
```
--power.hs
import System.Cmd(system)
import System.Environment(getArgs)
type Arg = String --A command-line argument
type Cmd = String --A command to execute
--paths to programs that will carry out the actions
shutdown_path = "C:\\Windows\\System32\\shutdown.exe"
rundll32_path = "C:\\Windows\\System32\\rundll32.exe"
--assoc list mapping arguments to the action that should be taken when that argument is received
cmds :: [(Arg, Cmd)]
cmds = [ ("shutdown", shutdown_path ++ " /s /t 0" ),
("sleep", rundll32_path ++ " powrprof.dll,SetSuspendState 0,1,0"),
("hibernate", shutdown_path ++ " /h" ), -- does not work
("lock", rundll32_path ++ " user32.dll,LockWorkStation" ),
("restart", shutdown_path ++ " -t 0 -r -f" ) ]
--gets the argument passed to the program. Calls error if there is not exactly one argument.
extractCmdOrFail :: IO Arg
extractCmdOrFail = getArgs >>= check
where check [s] = return s
check _ = error "Wrong Number of arguments"
--finds the command to execute from the given command-line arg. Calls error if no command is found.
findCmdOrFail :: Arg -> Cmd
findCmdOrFail s = check $ lookup s cmds
where check (Just s') = s'
check Nothing = error "Unknown command: " ++ s
--prompts the user to confirm whether or not they want to execute the command.
prompt :: Cmd -> Arg -> IO ()
prompt cmd name = putStr ("Execute " ++ name ++ "? (y/n)\n") >>
Solution
The code is short and nicely done, so I don't have much comment
In branch, you could use void instead of return ()
In your 'n' match, you use "getChar". I think it's to prevent the console from closing, right? Be aware that there is other ways, but it really depend on how you want to use your program.
Haskell use camelCase, so
Check
Your actual check functions are fine. But if you have more case like this, you should really consider this:
You could make the
The check call from findCmdOrFail will remain practically unchanged, you just have to add your error message
The interesting part is the one from
then your extractCmdOrFail will looks like this
In branch, you could use void instead of return ()
branch cmd 'y' = system cmd >> void
branch cmd 'n' = putStrLn "Command Cancelled" >> getChar >> voidIn your 'n' match, you use "getChar". I think it's to prevent the console from closing, right? Be aware that there is other ways, but it really depend on how you want to use your program.
Haskell use camelCase, so
shutdown_path and rundll32_path should be shutdownPath and rundll32PathCheck
Your actual check functions are fine. But if you have more case like this, you should really consider this:
You could make the
check function a top level one like thischeck :: String -> Maybe a -> a
check _ (Just s) = s
check errorMsg Nothing = error errorMsgThe check call from findCmdOrFail will remain practically unchanged, you just have to add your error message
The interesting part is the one from
extractCmdOrFail, you have to use an helper function that I didn't find on hackagewhenMaybe :: (a -> Bool) -> a -> Maybe a
whenMaybe predicate x = if predicate x then Just x else Nothingthen your extractCmdOrFail will looks like this
extractCmdOrFail = getArgs >>= check (whenMaybe $ {-your predicate-}) "Wrong Number of arguments"Code Snippets
branch cmd 'y' = system cmd >> void
branch cmd 'n' = putStrLn "Command Cancelled" >> getChar >> voidcheck :: String -> Maybe a -> a
check _ (Just s) = s
check errorMsg Nothing = error errorMsgwhenMaybe :: (a -> Bool) -> a -> Maybe a
whenMaybe predicate x = if predicate x then Just x else NothingextractCmdOrFail = getArgs >>= check (whenMaybe $ {-your predicate-}) "Wrong Number of arguments"Context
StackExchange Code Review Q#69543, answer score: 3
Revisions (0)
No revisions yet.