What does a double-dollar sign ($$) mean in Haskell? - haskell

I'm trying to hack together a new file format writer for pandoc using LaTeX.hs as a guide. Extensive use of a $$ operator is made, but I can't find this in the Haskell syntax documentation or even references to in in other projects. Here is an example:
let align dir txt = inCmd "begin" dir $$ txt $$ inCmd "end" dir
This almost looks like a concatenation operator of some kind, yet I can't make out how this is different from other concatenation operations. What is this operator, how does it work, and where is it documented?

This is a job for Hayoo or Hoogle. It's an operator defined in Text.Pandoc.Pretty.
($$) :: Doc -> Doc -> Doc infixr 5
a $$ b puts a above b.
Basically, it will make sure that a and b are on different lines, which leads to nicer LaTeX output:
\begin{dir}
txt
\end{dir}

Pandoc defines its own pretty-printing library internally but the operations (and the name of the type, Doc) are standard in Haskell pretty printing libraries. Pandoc also defines other familiars like vcat, hsep, <+> and so on; there are many pretty printing modules around, but they always support these operations.
> import Text.PrettyPrint
> text "hello" <> text "world"
helloworld
> text "hello" <+> text "world"
hello world
> text "hello" $$ text "world"
hello
world
> text "hello" <+> text "world" $$ text "goodbye" <+> text "world"
hello world
goodbye world
ghci here displays 'what the document will look like', crudely speaking.

Related

String Formatting columns in Haskell without Text.Printf

I am new to Haskell. I am at the last part of a school project. I have to take tuples and print them to an outfile and separate them by a tab column. So (709,4226408), (12965,4226412) and (5,4226016) should have and output of
709 4226408
12965 4226412
5 4226016
What I have been trying to do is this:
genOutput :: (Int, Int) -> String
genOutput (a,b) = (show a) ++ "\t" ++ (show b)
And this gives outputs like:
"709\t4226408"
"12965\t4226412"
"5\t4226016"
There are 3 things wrong with this. 1) Quotes still appear in the output. 2) The \t tab does not actually become a tab space. .Whenever I try to make an actual tab for the "" it just comes out as a " " space. 3) They are not aligned into columns like the above example. I know Text.Printf exists but we are not allowed to import anything other than:
import System.IO
import Data.List
import System.Environment
that's the output you get from GHCi I guess? Try to use putStrLn instead:
Prelude> genOutput (1,42)
"1\t42"
Prelude> putStrLn $ genOutput (1,42)
1 42
Why is that?
If you tell GHCi to evaluate an expression it will do so and (more or less) output it using show - show is designed to work with read and will usually output a value as if you would input it directly into Haskell. For a String that will include escape sequences and the "s
Now using putStrLn it will take the string and print it to stdout as you would expect.
Using print
Another reason could be that you use print to output your value - print is show + putStrLn so it'll show the values first re-introducing the escapes (as GHCi would) - so if you use print change it to putStrLn if you are using Strings

Process arrow key ANSI escape sequences on haskell stdin

I'm trying to process arrow key ANSI escape sequences i.e.
up - "\033[A"
down - "\033[B"
left - "\033[D"
right - "\033[C"
in my programme so when I press the up/down/left/right arrow key, it won't have to look like this:
% stack runghc test.hs
Input a name?
^[[A^[[B^[[C^[[D^
on my stdin, but rather I would like those keys to be suppressed or even better,
for them to actually work(i.e move the cursor left/right). My code is as follows:
main = do putStrLn "Input a name?"
name <- getLine
putStrLn $ ("His name is " ++ name)
Any help would be appreciated. Thanks in advance.
The easiest way to get readline-like functionality is to just use readline. For most simple use cases, rlwrap is good enough, as described in One REPL to bind them all?. If you need to do fancier integrations, you can use the readline package.
I had trouble installing the readline library due to some errors and decided to use the haskeline library, which is a more portable pure-haskell replacement for it.
Using its syntax and modifying the earlier code, I got:
main :: IO ()
main = do putStrLn "Input a name?"
runInputT defaultSettings insertion
where
insertion :: InputT IO ()
insertion = do
minput <- getInputLine ""
case minput of
Nothing -> return ()
Just input -> do outputStrLn $ "His name is " ++ input
Which solves the problem as I am now able to move my cursor with the arrow keys freely without having to see any trailing ANSI escape sequences as shown below:

Calculate simple math expression pass as a command line argument

I'm a newbie in Haskell and I'm lost. I was trying to parse a math expression, but really don't know how Haskell programming works well. So what I'm trying to write is a program to resolve a simple math expression. I'm looking for ideas on how I could resolve by giving arguments.
The command line could look like : ./math "3 + 2" or ./math "5 * 8"
My code looks like this:
import System.Environment (getArgs)
import Text.Printf
main :: IO ()
main = do
args <- getArgs
printf "%.2f" args[1] + args[2]
Haskell has no array[index] syntax. It does have list!!index syntax (which isn't really special syntax at all, !! is just an infix-function defined in the prelude). Note that Haskell indices are 0-based and unlike in Bash, the zeroth argument is not the command name itself, so you probably want indices 0 and 1.
Also, in Haskell function application binds more tightly than any operators. So, if you were to write
printf "%.2f" args!!0 + args!!1
it would parse as ((printf "%.2f" args)!!0) + (args!!1), which is obviously not right. You need to make explicit what precedence you want:
printf "%.2f" (args!!0 + args!!1)
or as we like to do it, with $ instead of parens:
printf "%.2f" $ args!!0 + args!!1
That's still not right, because the arguments come in as strings, but the addition should be performed on numbers. For this, you need to read the numbers; I'd suggest you do that separately:
import Text.Read (readMaybe)
main = do
args <- getArgs
let a, b :: Double
Just a = readMaybe $ args!!0
Just b = readMaybe $ args!!1
printf "%.2f" $ a + b
$ runhaskell Argsmath.hs 3 2
5.00
Of course this will not allow you to do stuff like ./math "5 * 8" because you have no means of parsing the *. For that, something read-based would be awkward; I suggest you check out parser combinator libraries, there are plenty of tutorials around; this one seems to be nice and simple.

Haskell: Why does this function keep asking for user input and not terminating

I'm learning some Haskell and I came across this small program
reverseLines :: String -> String
reverseLines input =
unlines (map reverse (lines input))
main :: IO ()
main = interact reverseLines
This program will keep asking the user for more input and reverse the input and print it on the screen.
Most of this is straight forward but one thing I can't wrap my head around is why does this function keeps running and ask the user for more input whereas if I just replace the reverseLines function with a function the simply returns some string it will not happen.
This program will stop after one execution:
foo input = "Stops"
main :: IO ()
main = interact foo
Why?
If you look at the source of interact you see this:
interact f = do s <- getContents
putStr (f s)
see the getContents? This is where the magic starts - it will read everything till EOF
Now in Haskell this is lazy-IO which can be bad but here is almost magical - see the string is read lazily and passed to your reverseLines - this one of course will only generate output as soon as it saw \n characters (the lines) and so it seems your program is some kind of REPL.
In the second one you don't consume any of the lazy-string at all so it stops ASAP
As I wrote in the comments you can play with this by either passing content into the program using a file (or echo) and pipes on the terminal:
echo "Hello World\nBye Bye" | runhaskell LazyIO.hs
or using CTRL-D to pass in the EOF yourself.
To get a feeling for it I would play with the functions more - what happens if you use something that needs to see the complete input first (try reverse without the maps)? What happens with words instead of lines, ...?
Have fun!

I need to adding text to the seem variable

I need your help please, my question is,
How i can make like this in haskell:
dim myVar = "text 1"
myVar += " and " + "text 2"
The first thing you need to understand about Haskell is that you don't have variables, you only have values bound to names. Variables don't exists because values are immutable. This means that they never change. To change them is a compile time error.
At first this seems like a huge disadvantage, but in time you'll come to find that in most cases you don't need mutable values (and there are ways to do mutable values, but that's an advanced topic).
So, how would you write a function to do this? You could put in a file these contents:
module Main where
appendText :: String -> String -- Takes a string, returns a string
appendText text = text ++ " and " ++ "text 2"
main :: IO () -- An IO action with no result (think none or null)
main = do
let myText = "text 1"
putStrLn (appendText myText)
Since it seems that you have not yet introduced yourself fully to Haskell, I would recommend Learn You a Haskell, my favorite tutorial for the language. It starts with the very basics and works it way up to fairly advanced topics.

Resources