Reputation: 53786
I'm attempting to use this library to access IP :
http://jacob.stanley.io/2010/08/12/ip-addresses-and-mac-addresses-in-haskell/
src :
import Network.Info
main = do
ns <- getNetworkInterfaces
mapM_ (putStr . showInterface) ns
showInterface n = name n ++ "\n"
++ " IPv4: " ++ show (ipv4 n) ++ "\n"
++ " IPv6: " ++ show (ipv6 n) ++ "\n"
++ " MAC: " ++ show (mac n) ++ "\n"
How can I just access the IPv4 address via ghci in a var ?
something like :
let ipv4 = filterIpV4Address(ns)
ns
is of type ns :: [NetworkInterface]
and contains all the network interfaces. I'm new to Haskell and do not understand this code.
How is variable "n" set in line showInterface n = name n ++ "\n"
Is it somehow set at line mapM_ (putStr . showInterface) ns
?
Update :
Prelude Network.Info Main> ns <- getNetworkInterfaces
Prelude Network.Info Main> ns
[NetworkInterface {name = "Local Area Connection", ipv4 = 169.254.166.181, ipv6
= fe80:0:0:0:94d4:87b2:7435:a6b5, mac = e8:11:32:d4:bf:04},NetworkInterface {nam
e = "Wireless Network Connection", ipv4 = 192.168.1.12, ipv6 = fe80:0:0:0:b593:3
47d:11d0:916f, mac = 00:1b:b1:28:a7:96},NetworkInterface {name = "Bluetooth Netw
ork Connection", ipv4 = 169.254.131.172, ipv6 = fe80:0:0:0:6cc5:4071:a29b:83ac,
mac = 90:a4:de:9c:a2:7a},NetworkInterface {name = "VirtualBox Host-Only Network"
, ipv4 = 192.168.56.1, ipv6 = fe80:0:0:0:91e2:7d75:e6f7:d90f, mac = 0a:00:27:00:
00:00},NetworkInterface {name = "Loopback Pseudo-Interface 1", ipv4 = 127.0.0.1,
ipv6 = 0:0:0:0:0:0:0:1, mac = 00:00:00:00:00:00},NetworkInterface {name = "Loca
l Area Connection* 12", ipv4 = 0.0.0.0, ipv6 = fe80:0:0:0:0:100:7f:fffe, mac = 0
0:00:00:00:00:00},NetworkInterface {name = "isatap.home", ipv4 = 64.3.66.5, ipv6
= fe80:0:0:0:0:5efe:c0a8:10c, mac = 00:00:00:00:00:00},NetworkInterface {name =
"isatap.{7F25AE4D-EDF3-491F-ADED-642C194C94D9}", ipv4 = 0.0.0.0, ipv6 = fe80:0:
0:0:0:5efe:c0a8:3801, mac = 00:00:00:00:00:00}]
So how to extract value : 192.168.1.12 ?
Upvotes: 1
Views: 467
Reputation: 15967
From the documentation you get the definition of NetworkInterface
data NetworkInterface = NetworkInterface { name :: String
, ipv4 :: IPv4
, ipv6 :: IPv6
, mac :: MAC}
this tells you that if you want to access name
etc. you have accessor function of the same name, with the type signature name :: NetworkInterface -> String
(analogously for the others) - thus if you want to extract the name from a list of network interfaces you are looking for something like ?? :: (NetworkInterfaces -> String) -> [NetworkInterfaces] -> [String]
which is a special case of this type signature ?? :: (a -> b) -> [a] -> [b]
put it into hoogle and you see a function called map
as the first result.
So in order to collect the network names you only need to map names ns
.
But if you want to apply this functions to the result of getNetworkInterfaces
there is this IO
indicator that is not fitting into this type signature; but there exists a function called fmap
- a more general version of the function map
we already saw that can help us.
fmap
takes a container (in this case IO
and a function that works on containees and applies the function in a sensible way to said containees, (btw. all containers that supply such a function are called Functors
).
So in order to get your names from getNetworkInterfaces
directely you need to put in your ghci:
Prelude> ns <- fmap (map name) getNetworkInterfaces
or with 'backtick-syntax'
Prelude> ns <- map name `fmap` getNetworkInterfaces
and if you import Control.Applicative
you get this very handy infix operator <$>
that lets you write it as map name <$> getNetworkInterfaces
showInterface
is actually a function - its type signature which is omitted - is showInterface :: NetworkInterface -> String
which means it takes a NetworkInterface
and produces a String
. So the n
is actually a network interface which has (by the data declaration I posted) 4 accessor functions for getting name
, ipv4
, ipv6
, and mac
. Unfortunately the putStr
function which produces output to stdout
has type signature String -> IO ()
which would only work for name
which is already a String
, to get the remaining 3 to work we have to use haskell's toString()
-method which is called show
, the rest that showInterface
does is stitching String
s together with the ++
operator. (Sidenote: (++)
stitches together two lists of the same type and String
s are just [Char]
= list of Char
)
So what does mapM_
do at last - it works very analogous to map
(hence the name), but it allows for side effects to happen and fortunately enough printing to stdout (with putStr
) is such a side effect. Note that there are two functions very similar mapM
and mapM_
the underscore you might see from time to time in haskell-land indicates that something is thrown away/not needed, in this case the result - where in this case mapM
would produce a IO [()]
, mapM_
just forgets the list and produces IO ()
(speak IO unit - which you can think of void
in C-like languages, my mnemonic is void
has io in it but with something around to hide it and spelled in the wrong order).
And incidentally the type signature for main
which is also omitted is main :: IO ()
which fits exactly to the mapM_
.
Upvotes: 3