ssadler / hawk

Awk for Hoodlums
BSD 3-Clause "New" or "Revised" License
35 stars 2 forks source link

extra newline #37

Open gelisam opened 11 years ago

gelisam commented 11 years ago

I don't understand where the extra newline comes from.

> seq 3 | hsl 'unlines . P.reverse . lines'
3
2
1

> 

In hsl, there was no spurious newline:

> seq 3 | hsl reverse
3
2
1
> 

Neither using ghc -e:

seq 3 | ghc -e 'interact (unlines . reverse . lines) 3 2 1

Without looking at the code, I strongly suspect a putStrLn where a putStr should be.

melrief commented 11 years ago

I found the bug but I don't know how to fix it. Let me explain. The output of Hawk is produced by the function printRows, that takes in input something that instantiate Rows and print one line per row:

printRows :: forall a . (Rows a) => Bool -> a -> IO ()
printRows b = printRows_ . repr
    where printRows_ [] = return ()
               printRows_ (x:xs) = do
               f x
               handle ioExceptionsHandler (continue xs)
               f = if b then handleErrors . C8.putStrLn else C8.putStrLn
               continue xs = IO.hFlush IO.stdout >> printRows_ xs
               ioExceptionsHandler e = case ioe_type e of
                                    ResourceVanished -> return ()
                                    _ -> IO.hPrint IO.stderr e

the function f (I will change its name, I swear!) is in charge of printing a single row and it does it by using putStrLn. So effectively there is a '\n' added to each row. But that's correct, because in this way you can write:

> hawk -e '[1,2,3]'
1
2
3

Now, if the expression to be printed out is a ByteString, Hawk threats it like a single row. If that ByteString has at the end a newline, then it will be like using putStrLn on "3\n2\n1\n":

ghci> P.putStrLn "3\n2\n1\n"
3
2
1

>

The right way to use Hawk is to avoid the final unlines: why create a new string if you can print lists?

> seq 1 3 | hawk 'P.reverse . lines'
3
2
1

or as I prefer

seq 1 3 | hawk -d P.reverse
3
2
1

But apparently this is misleading. A hack/solution could be to check if the last character of a ByteString is a newline and ignore it. It is a hack but, again, this bug is hardcoded in the way Hawk shows values.

gelisam commented 11 years ago

Ah! Your explanation makes perfect sense, and guides me towards a more convenient use of the tool. Let's leave the "bug" unfixed and add your explanation as an FAQ. This way, users who encounter this will look it up, and return as better hawkers.

gelisam commented 11 years ago

Or maybe alias unlines to error "plase read the FAQ" :)