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
Related
How can I write this code without repeating (c !! x) where is x = [0..7], using list comprehension is better but I couldn't figure how to write it
show (EOBoard f c r) = "EOBoard\n" ++ "Foundations "
++ show f ++ "\n" ++ "Columns \n"
++ show (c!!0) ++ "\n" ++ show (c!!1) ++ "\n"
++ show (c!!2) ++ "\n" ++ show (c!!3) ++ "\n"
++ show (c!!4) ++ "\n" ++ show (c!!5) ++ "\n"
++ show (c!!6) ++ "\n" ++ show (c!!7) ++ "\n"
++ "Reserves " ++ show r
Let's start by getting rid of all those manual line breaks.
import Data.List
show (EOBoard f c r) = intercalate "\n" $
[ "EOBoard"
, "Foundations " ++ show f
, "Columns"
, show (c!!0)
, show (c!!1)
, show (c!!2)
, show (c!!3)
, show (c!!4)
, show (c!!5)
, show (c!!6)
, show (c!!7)
, "Reserves " ++ show r]
Note: if you want a line break at the end too, use unlines instead of intercalate.
As you noticed, there's a rather repetitive section. Also, those !! applications are kind of expensive. A list comprehension solves both problems, but I'd use map instead.
show (EOBoard f c r) = intercalate "\n" $
[ "EOBoard"
, "Foundations " ++ show f
, "Columns" ] ++
map show c ++
["Reserves " ++ show r]
(map show c could be replaced by [show x | x <- c] if you prefer.)
There's still something funny; Show really isn't for pretty-printing. show shouldn't insert line breaks. You probably actually want to write a custom pretty-printing function instead.
What you wrote is equivalent to
show (EOBoard f c r) = "EOBoard\n" ++ "Foundations "
++ show f ++ "\n" ++ "Columns \n" ++
++ concat [ show s ++ "\n" | s <- take 8 c]
++ "\n" ++ "Reserves " ++ show r
which is equivalent to
show (EOBoard f c r) = "EOBoard\n" ++ "Foundations "
++ show f ++ "\n" ++ "Columns \n" ++
++ [ ch | s <- take 8 c, ch <- show s ++ "\n" ]
++ "\n" ++ "Reserves " ++ show r
or, using the concat more instead of inlining it, it is equivalent to
show (EOBoard f c r) = concat (
[ "EOBoard\n", "Foundations ", show f, "\n", "Columns \n" ]
++ [ show s ++ "\n" | s <- take 8 c]
++ ["\n" , "Reserves " , show r] )
which is normally written with the $ operator, as
show (EOBoard f c r) = concat $
[ "EOBoard\n", "Foundations ", show f, "\n", "Columns \n" ]
++ [ show s ++ "\n" | s <- take 8 c]
++ ["\n" , "Reserves " , show r]
I am not able to print outputs in multiple lines with the following code.
average l = (sum l) / (fromIntegral (length l))
readDoubles s1 s2 = putStr (s1++"\n"++s2) >>
do x <- readDoublesHelper; return ("The average is " ++ (show (average x)) ++ " \n" ++ "The maximum is " ++ (show (maximum x)) ++ "\n" ++ "The minimum is " ++ (show (minimum x)) ++ "\n")
readDoublesHelper = putStr "Enter a number: " >>
do line <- getLine;
if line == "done"
then return [];
else do xs <- (readDoublesHelper)
return ((read line :: Float): xs)
interface = readDoubles "Enter some numbers." "When finished, type ’done’. \n"
The output that I get is
*Main> interface
Enter some numbers.
When finished, type ’done’.
Enter a number: 2
Enter a number: 3
Enter a number: 4
Enter a number: 5
Enter a number: 6
Enter a number: 7
Enter a number: done
"The average is 4.5 \nThe maximum is 7.0\nThe minimum is 2.0\n"
But I want the output to be printed like this
The average is 4.5
The maximum is 7.0
The minimum is 2.0
Do notice "The average is 4.5 \nThe maximum is 7.0\nThe minimum is 2.0\n" is actually not printed
Reformatting readDoubles:
readDoubles s1 s2 = do
putStr (s1++"\n"++s2)
x <- readDoublesHelper
return ("The average is " ++ (show (average x)) ++ " \n" ++ "The maximum is " ++ (show (maximum x)) ++ "\n" ++ "The minimum is " ++ (show (minimum x)) ++ "\n")
We can see that result is "returned" rather than "printed"
As the type signature of readDoubles is:
readDoubles :: String -> String -> IO String
It just returns a lifted string. Since GHCi will print out the final result of the function, you're getting "The average is 4.5 \nThe maximum is 7.0\nThe minimum is 2.0\n" as output (the return value of the function)
However, from you description, I guess you just like to print out the result, so it should be:
readDoubles :: String -> String -> IO ()
readDoubles s1 s2 = do
putStr (s1++"\n"++s2)
x <- readDoublesHelper
putStrLn ("The average is " ++ (show (average x)) ++ " \n" ++ "The maximum is " ++ (show (maximum x)) ++ "\n" ++ "The minimum is " ++ (show (minimum x)) ++ "\n")
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.
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
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.