blue-sky
blue-sky

Reputation: 53786

Access IPV4 address of local linux machine

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

Answers (1)

epsilonhalbe
epsilonhalbe

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

EDIT

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 Strings together with the ++ operator. (Sidenote: (++) stitches together two lists of the same type and Strings 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

Related Questions