A mystery involving putStrLn - haskell

Why does the piece of code below produce the error parse error on input ‘putStrLn’?
main = do line <- fmap reverse getLine
putStrLn $ "You said " ++ line ++ " backwards!"
putStrLn $ "Yes, you said " ++ line ++ " backwards!"
<interactive>:11:4: error: parse error on input ‘putStrLn’
Also, why does the following piece of code produce the error parse error on input ‘let’?
main = do line <- getLine
let line' = reverse line
putStrLn $ "You said " ++ line' ++ " backwards!"
putStrLn $ "Yes, you said " ++ line' ++ " backwards!"
<interactive>:31:4: error: parse error on input ‘let’

Both snippets have the same problem. If you put the first action of a do block on the same line as the do itself, you still have to indent the rest of the actions in the do block as far as the first one. Two choices to fix it:
main = do line <- fmap reverse getLine
putStrLn $ "You said " ++ line ++ " backwards!"
putStrLn $ "Yes, you said " ++ line ++ " backwards!"
or
main = do
line <- fmap reverse getLine
putStrLn $ "You said " ++ line ++ " backwards!"
putStrLn $ "Yes, you said " ++ line ++ " backwards!"

It also works when explicit separators are used throughout:
main = do { line <- fmap reverse getLine ;
putStrLn $ "You said " ++ line ++ " backwards!" ;
putStrLn $ "Yes, you said " ++ line ++ " backwards!" }
main = do { line <- getLine ;
let { line' = reverse line } ; -- NB let's { }s
putStrLn $ "You said " ++ line' ++ " backwards!" ;
putStrLn $ "Yes, you said " ++ line' ++ " backwards!" }
This is not a substitute for the good indentation style, but an addition to it.

Related

Basic error with `putStrLn` in Haskell. VScode extension Haskelly [duplicate]

This question already has answers here:
A mystery involving putStrLn
(2 answers)
Closed 3 years ago.
main = do line <- getLine
let line' = reverse line
putStrLn $ "You said " ++ line' ++ " backwards!"
putStrLn $ "Yes, you really said " ++ line ++ " backwards!"
Error:
$ stack runhaskell "c:\Users\FruitfulApproach\Desktop\Haskell\test.hs"
C:\Users\FruitfulApproach\Desktop\Haskell\test.hs:4:5: error:
parse error on input `putStrLn'
|
4 | putStrLn $ "You said " ++ line' ++ " backwards!"
| ^^^^^^^^
I've also tried it with a single tab on the indented lines.
Here's my tabs -> spaces setting:
I've also tried restarting VSCode.
Thanks in advance!
I believe your code is insufficiently indented. Try this:
main = do line <- getLine
let line' = reverse line
putStrLn $ "You said " ++ line' ++ " backwards!"
putStrLn $ "Yes, you really said " ++ line ++ " backwards!"
Specifically, your lines following the do should be indented just as much as the thing that comes after it, namely line <- getLine.

How do I show two inputs are the same or not

I'm trying to just compare two user inputs but I can't seem to get it working and constantly get parse errors. Any help will be appreciated.
main = do
foo <- putStrLn "Enter two numbers."
numone <- getLine
numtwo <- getLine
putStrLn $ ("You entered " ++ numone ++ " and " ++ numtwo)
if
numone == numtwo
then
putStrLn "They are the same"
else
putStrLn "They are not the same"
The errors probably arise through to small changes in indentation between the local version, and the one posted here. Indentation in Haskell is quite important, since the compiler uses it to understand where certain "blocks" begin and end.
Furthermore you can remove the foo <- part (well this is not wrong, but quite useless). So after reformatting we get:
main = do
putStrLn "Enter two numbers."
numone <- getLine
numtwo <- getLine
putStrLn $ ("You entered " ++ numone ++ " and " ++ numtwo)
if numone == numtwo
then
putStrLn "They are the same"
else
putStrLn "They are not the same"
Furthermore now you compare two strings. You can convert these to Ints (or other readable types) with for example readLn :: Read a => IO a:
main = do
putStrLn "Enter two numbers."
numone <- readLn :: IO Int
numtwo <- readLn :: IO Int
putStrLn $ ("You entered " ++ show numone ++ " and " ++ show numtwo)
if numone == numtwo
then
putStrLn "They are the same"
else
putStrLn "They are not the same"
You have mixed tabs and spaces in your code snippet, and the blank line in between your print and your if expression is indented by less than the other lines are. Your whole do-block must have the same initial indentation. I suggest using only spaces (or only tabs, if you prefer) so that it's harder to accidentally wind up with misaligned code that looks correctly aligned.
I see I answered on the basis of code OP never wrote, because of an incorrect edit someone else made. It "fixed" the indentation but was actually still wrong for a different reason. Oh well, it's still an indentation problem but not one to do with mixing spaces and tabs.

Haskell, I need help as I can't seem to work out what I have done wrong. (Basic)

I'm new to Haskell and am trying to learn using things like learn you a Haskell. Can someone explain what is wrong with my code as I don't really know how to read error messages yet. All I can tell so far is that the let statements aren't correct but I need them to work somehow because without them the (show (typeOf numone/numtwo)) only shows the type of either 'numone' or 'numtwo' and not the inputted values from the getLine.
What I am trying to do is compare the inputs and show the types of the inputs but this is as far I can go without some help.
import Data.Typeable
main = do
putStrLn "Enter two statements."
numone <- getLine
numtwo <- getLine
putStrLn $ ("You entered " ++ show numone ++ (show (typeOf numone)) ++ " and " ++ show numone ++ (show (typeOf numone)))
let numone = getLine
let numtwo = getLine
if numone == numtwo
then
putStrLn $ "They are the same and their types are " ++ (show (typeOf numone)) ++ " and " ++ (show (typeOf numtwo))
else
putStrLn $ "They are not the same"
Error message;
• No instance for (Eq (IO String)) arising from a use of ‘==’
• In the expression: numone == numtwo
In a stmt of a 'do' block:
if numone == numtwo then
putStrLn
$ "They are the same and their types are "
++ (show (typeOf numone)) ++ " and " ++ (show (typeOf numtwo))
else
putStrLn $ "They are not the same"
In the expression:
do putStrLn "Enter two statements."
numone <- getLine
numtwo <- getLine
putStrLn
$ ("You entered "
++
show numone
++
(show (typeOf numone))
++ " and " ++ show numone ++ (show (typeOf numone)))
....
|
10 | if numone == numtwo
| ^^^^^^^^^^^^^^^^
The output should be something like (depending on the input of getLine);
> You entered A123[String] and B456[String]
> They are the same and their types are [String] and [String]
or
They are not the same
If your code is exactly as shown in the question, then the first problem is indentation.
Indentation matters in Haskell (like in Python), unless you use the { ... ; ... ; ... } syntax.
The second problem is that getLine is an action in the IO-monad, so you can't use let, but must use a monadic binding.
Oh, and the second binding overrides the first. So while using the name a second time is not wrong, it's bad style.
The third thing (it's not really a problem) is that the code as written will assign static types to numone and numtwo - it's not somehow like entering different values will change their type. getLine has type
getLine :: IO String
so you'll always see [Char] (aka String) as the type.
The fourth problem is that you used numone twice in the first output, instead of numone and numtwo.
Edit
I completely removed the second input (the former let-statements) according to the comments.
Here's the corrected program:
import Data.Typeable
main :: IO ()
main = do
putStrLn "Enter two statements."
numone <- getLine
numtwo <- getLine
putStrLn $ ("You entered " ++ show numone ++ (show (typeOf numone)) ++ " and " ++ show numtwo ++ (show (typeOf numtwo)))
if numone == numtwo then
putStrLn $ "They are the same and their types are " ++ (show (typeOf numone)) ++ " and " ++ (show (typeOf numtwo))
else
putStrLn $ "They are not the same"
return ()
Example session fro ghci:
*Main> main
Enter two statements.
A123
B456
You entered "A123"[Char] and "B456"[Char]
They are not the same
*Main> main
Enter two statements.
A123
A123
You entered "A123"[Char] and "A123"[Char]
They are the same and their types are [Char] and [Char]
*Main>
So that should do what you want.
Let me emphasize again: You'll always get [Char] as the type, no matter what you do. You can't assign dynamic types based on input. And in general, the Haskell typesystem is static; while there are some advanced constructions like Data.Typeable, I wouldn't recommend them for beginners. Your mental image should be "when I compile the program, the Haskell typechecker will assign a single static type to every subexpression". You can actually ask the typechecker for those by using :t in the REPL:
*Main> :t getLine
getLine :: IO String

Query IP2Location LITE binary databases using Haskell?

I would like to use Haskell to query the IP2Location LITE binary databases from here. So I am wondering if there are any existing modules or codes to read the databases?
I don't know about ip2location, but there is geoip2 native module that works with Geoip2 database. Depending on what you want to use it for it may work for you.
You can use the following example code from Github:
import IP2Location
main :: IO ()
main = do
let myfile = "IPV6-COUNTRY-REGION-CITY-LATITUDE-LONGITUDE-ZIPCODE-TIMEZONE-ISP-DOMAIN-NETSPEED-AREACODE-WEATHER-MOBILE-ELEVATION-USAGETYPE.BIN"
meta <- doInit myfile
result <- doQuery myfile meta "8.8.8.8"
putStrLn $ "country_short: " ++ (show (country_short result))
putStrLn $ "country_long: " ++ (show (country_long result))
putStrLn $ "region: " ++ (show (region result))
putStrLn $ "city: " ++ (show (city result))
putStrLn $ "isp: " ++ (show (isp result))
putStrLn $ "latitude: " ++ (show (latitude result))
putStrLn $ "longitude: " ++ (show (longitude result))
putStrLn $ "domain: " ++ (show (domain result))
putStrLn $ "zipcode: " ++ (show (zipcode result))
putStrLn $ "timezone: " ++ (show (timezone result))
putStrLn $ "netspeed: " ++ (show (netspeed result))
putStrLn $ "iddcode: " ++ (show (iddcode result))
putStrLn $ "areacode: " ++ (show (areacode result))
putStrLn $ "weatherstationcode: " ++ (show (weatherstationcode result))
putStrLn $ "weatherstationname: " ++ (show (weatherstationname result))
putStrLn $ "mcc: " ++ (show (mcc result))
putStrLn $ "mnc: " ++ (show (mnc result))
putStrLn $ "mobilebrand: " ++ (show (mobilebrand result))
putStrLn $ "elevation: " ++ (show (elevation result))
putStrLn $ "usagetype: " ++ (show (usagetype result))
You'll need to install the IP2Location package using cabal:
cabal install IP2Location
Hackage page: https://hackage.haskell.org/package/ip2location-8.0.4/docs/IP2Location.html

Haskell desugar syntax

Shuklan's Haskell Lecture wanted the following code desugared:
main = do
putStrLn "Enter name:"
name <- getLine
putStrLn ("Hi " ++ name)
I came up with:
main = putStrLn "Enter name:" >> getLine >>= \str -> putStrLn ("Hi " ++ str)
He revealed:
main = putStrLn "Enter name:" >> getLine >>= putStrLn . ("Hi " ++)
Never seen that syntax before, how does it work?
The snippets are identical, the latter just uses point free style (also punningly referred to as "pointless style").
The central point is that ("Hi " ++) is a partially applied (++) that prepends "Hi " to the input.
This function is composed (using .) with putStrLn to get a function that prepends "Hi " to the input and then prints it.
This is exactly what your more explicit lambda does.

Resources