Reputation: 2024
I want to write a small script which calculates the differences between two timestamps and returns the hours formatted like hh:mm
. For example:
./calc-hours 8 32 15 42
should return 7:10h
Note: I don't really care about edge cases which go from 23:00 to 01:00. The code below may even be wrong still but I have a different problem.
The code I came up with is this:
import Text.Printf
import System.Environment
import Data.List
-- Time in minutes starting from 00:00h
tm h m = h * 60 + m
-- Time difference between two timestamps in minutes
td h1 m1 h2 m2 = (tm h2 m2) - (tm h1 m1)
-- Print time difference formatted in hh:mm format
ptdf (h1:m1:h2:m2:hms)
| hms /= [] = printf "usage: calc-hours <h1> <m1> <h2> <m2> %s" (show "test")
| otherwise = printf "%s:%s until %s:%s => %d:%dh" (show h1) (show m1) (show h2) (show m2) h3 m3
where
d = td h1 m1 h2 m2;
h3 = div d 60;
m3 = mod d 60
main = do
args <- getArgs
putStrLn . ptdf args
I tested these tm
, td
and ptdf
functions directly with ghci
and they worked so far. When I compile this little script with ghc
I get the following error:
☁ ghc calc-hours.hs && ./calc-hours 8 32 15 42
[1 of 1] Compiling Main ( calc-hours.hs, calc-hours.o )
calc-hours.hs:18:5: error:
• Couldn't match expected type ‘IO b’
with actual type ‘a0 -> IO ()’
• Probable cause: ‘(.)’ is applied to too few arguments
In a stmt of a 'do' block: putStrLn . ptdf args
In the expression:
do args <- getArgs
putStrLn . ptdf args
In an equation for ‘main’:
main
= do args <- getArgs
putStrLn . ptdf args
• Relevant bindings include
main :: IO b (bound at calc-hours.hs:16:1)
|
18 | putStrLn . ptdf args
| ^^^^^^^^^^^^^^^^^^^^
Could someone please explain what is going wrong here and how I can fix it? I was under the impression that ptdf
returns a String or at least something with which putStrLn
can work with. :t printf
also does not really point me in any direction.
Prelude> :t printf
printf :: PrintfType r => String -> r
Upvotes: 1
Views: 103
Reputation: 476557
The problem is not the printf
, the problem is that your ptdf args
returns an PrintfType r => r
. Here in this case, the idea is that this will use String
. You are writing putStrLn . ptdf args
, so you are constructing a function, but putStrLn . ptdf args
should be an IO a
since getArgs
is an IO [String]
.
main :: IO ()
main = do
args <- getArgs
ptdf args
For your ptdf
function, you will need to parse the parameters with read
:
ptdf :: [String] -> IO ()
ptdf [h1, m1, h2, m2] = printf "%s:%s until %s:%s => %d:%dh\n" h1 m1 h2 m2 h3 m3
where d = td (read h1) (read m1) (read h2) (read m2)
h3 = div d 60
m3 = mod d 60
ptdf _ = printf "usage: calc-hours <h1> <m1> <h2> <m2> %s\n" "test"
or we can let ptdf
generate a String
:
ptdf :: [String] -> String
ptdf [h1, m1, h2, m2] = printf "%s:%s until %s:%s => %d:%dh" h1 m1 h2 m2 h3 m3
where d = td (read h1) (read m1) (read h2) (read m2)
h3 = div d 60
m3 = mod d 60
ptdf _ = printf "usage: calc-hours <h1> <m1> <h2> <m2> %s" "test"
and then print that string with:
main :: IO ()
main = do
args <- getArgs
putStrLn (ptdf args)
Upvotes: 1