views:

125

answers:

2

This question here is related to http://stackoverflow.com/questions/3066956/haskell-input-return-tuple

I wonder how we can passes the input from monad IO to another function in order to do some computation.

Actually what i want is something like

-- First Example
test = savefile investinput 
-- Second Example
maxinvest :: a
maxinvest = liftM maximuminvest maxinvestinput

maxinvestinput :: IO()
maxinvestinput = do
    str <- readFile "C:\\Invest.txt"
    let cont = words str
    let mytuple = converttuple cont
    let myint = getint mytuple

    putStrLn ""

-- Convert to Tuple
converttuple :: [String] -> [(String, Integer)]
converttuple [] = []
converttuple (x:y:z) = (x, read y):converttuple z

-- Get Integer
getint :: [(String, Integer)] -> [Integer]
getint [] = []
getint (x:xs) = snd (x) : getint xs

-- Search Maximum Invest
maximuminvest :: (Ord a) => [a] -> a
maximuminvest [] = error "Empty Invest Amount List"
maximuminvest [x] = x
maximuminvest (x:xs)   
     | x > maxTail = x  
     | otherwise = maxTail  
     where maxTail = maximuminvest xs 

In the second example, the maxinvestinput is read from file and convert the data to the type maximuminvest expected. Please help.

Thanks.

+2  A: 

I'm not sure I understand your question, but I'll answer as best I can. I've simplified things a bit to get at the "meat" of the question, if I understand it correctly.

maxInvestInput :: IO [Integer]
maxInvestInput = liftM convertToIntegers (readFile "foo")

maximumInvest :: Ord a => [a] -> a
maximumInvest = blah blah blah

main = do
   values <- maxInvestInput
   print $ maximumInvest values

OR

main = liftM maximumInvest maxInvestInput >>= print
Gregory Higley
I need to create a function which accept IO using monad then this data enter by user is passes to another function as input as highlighted here. maxinvest :: amaxinvest = liftM maximuminvest maxinvestinput
peterwkc
I can't understand what you're asking for. It seems like this answers your question, but your type signature for `maxinvest` makes no sense. It can't be of any type `a`; it can only be of a particular type, namely `IO Integer`. It couldn't even be `IO a`, as your other functions assume that there are integers.
Antal S-Z
+6  A: 

First, I think you're having some basic issues with understanding Haskell, so let's go through building this step by step. Hopefully you'll find this helpful. Some of it will just arrive at the code you have, and some of it will not, but it is a slowed-down version of what I'd be thinking about as I wrote this code. After that, I'll try to answer your one particular question.


I'm not quite sure what you want your program to do. I understand that you want a program which reads as input a file containing a list of people and their investments. However, I'm not sure what you want to do with it. You seem to (a) want a sensible data structure ([(String,Integer)]), but then (b) only use the integers, so I'll suppose that you want to do something with the strings too. Let's go through this. First, you want a function that can, given a list of integers, return the maximum. You call this maximuminvest, but this function is more general that just investments, so why not call it maximum? As it turns out, this function already exists. How could you know this? I recommend Hoogle—it's a Haskell search engine which lets you search both function names and types. You want a function from lists of integers to a single integer, so let's search for that. As it turns out, the first result is maximum, which is the more general version of what you want. But for learning purposes, let's suppose you want to write it yourself; in that case, your implementation is just fine.

Alright, now we can compute the maximum. But first, we need to construct our list. We're going to need a function of type [String] -> [(String,Integer)] to convert our formattingless list into a sensible one. Well, to get an integer from a string, we'll need to use read. Long story short, your current implementation of this is also fine, though I would (a) add an error case for the one-item list (or, if I were feeling nice, just have it return an empty list to ignore the final item of odd-length lists), and (b) use a name with a capital letter, so I could tell the words apart (and probably a different name):

tupledInvestors :: [String] -> [(String, Integer)]
tupledInvestors []              = []
tupledInvestors [_]             = error "tupledInvestors: Odd-length list"
tupledInvestors (name:amt:rest) = (name, read amt) : tupledInvestors rest

Now tat we have these, we can provide ourselves with a convenience function, maxInvestment :: [String] -> Integer. The only thing missing is the ability to go from the tupled list to a list of integers. There are several ways to solve this. One is the one you have, though that would be unusual in Haskell. A second would be to use map :: (a -> b) -> [a] -> [b]. This is a function which applies a function to every element of a list. Thus, your getint is equivalent to the simpler map snd. The nicest way would probably be to use Data.List.maximumBy :: :: (a -> a -> Ordering) -> [a] -> a. This is like maximum, but it allows you to use a comparison function of your own. And using Data.Ord.comparing :: Ord a => (b -> a) -> b -> b -> Ordering, things become nice. This function allows you to compare two arbitrary objects by converting them to something which can be compared. Thus, I would write

maxInvestment :: [String] -> Integer
maxInvestment = maximumBy (comparing snd) . tupledInvestors

Though you could also write maxInvestment = maximum . map snd . tupledInvestors.

Alright, now on to the IO. Your main function, then, wants to read from a specific file, compute the maximum investment, and print that out. One way to represent that is as a series of three distinct steps:

main :: IO ()
main = do dataStr <- readFile "C:\\Invest.txt"
          let maxInv = maxInvestment $ words dataStr
          print maxInv

(The $ operator, if you haven't seen it, is just function application, but with more convenient precedence; it has type (a -> b) -> a -> b, which should make sense.) But that let maxInv seems pretty pointless, so we can get rid of that:

main :: IO ()
main = do dataStr <- readFile "C:\\Invest.txt"
          print . maxInvestment $ words dataStr

The ., if you haven't seen it yet, is function composition; f . g is the same as \x -> f (g x). (It has type (b -> c) -> (a -> b) -> a -> c, which should, with some thought, make sense.) Thus, f . g $ h x is the same as f (g (h x)), only easier to read.

Now, we were able to get rid of the let. What about the <-? For that, we can use the =<< :: Monad m => (a -> m b) -> m a -> m b operator. Note that it's almost like $, but with an m tainting almost everything. This allows us to take a monadic value (here, the readFile "C:\\Invest.txt" :: IO String), pass it to a function which turns a plain value into a monadic value, and get that monadic value. Thus, we have

main :: IO ()
main = print . maxInvestment . words =<< readFile "C:\\Invest.txt"

That should be clear, I hope, especially if you think of =<< as a monadic $.

I'm not sure what's happening with testfile; if you edit your question to reflect that, I'll try to update my answer.


One more thing. You said

I wonder how we can passes the input from monad IO to another function in order to do some computation.

As with everything in Haskell, this is a question of types. So let's puzzle through the types here. You have some function f :: a -> b and some monadic value m :: IO a. You want to use f to get a value of type b. This is impossible, as I explained in my answer to your other question; however, you can get something of type IO b. Thus, you need a function which takes your f and gives you a monadic version. In other words, something with type Monad m => (a -> b) -> (m a -> m b). If we plug that into Hoogle, the first result is Control.Monad.liftM, which has precisely that type signature. Thus, you can treat liftM as a slightly different "monadic $" than =<<: f \liftM` mappliesfto the pure result ofm(in accordance with whichever monad you're using) and returns the monadic result. The difference is thatliftMtakes a pure function on the left, and=<<` takes a partially-monadic one.

Another way to write the same thing is with do-notation:

do x <- m
   return $ f x

This says "get the x out of m, apply f to it, and lift the result back into the monad." This is the same as the statement return . f =<< m, which is precisely liftM again. First f performs a pure computation; its result is passed into return (via .), which lifts the pure value into the monad; and then this partially-monadic function is applied, via =<,, to m.

It's late, so I'm not sure how much sense that made. Let me try to sum it up. In short, there is no general way to leave a monad. When you want to perform computation on monadic values, you lift pure values (including functions) into the monad, and not the other way around; that could violate purity, which would be Very Bad™.


I hope that actually answered your question. Let me know if it didn't, so I can try to make it more helpful!

Antal S-Z
Why function application has type signature (a -> b) -> a -> b ? Why function composition has type signature(b -> c) -> (a -> b) -> a -> c ? What is this =<< :: Monad m => (a -> m b) -> m a -> m b ?Besides that, i also no understand all topic related to monad which mentioned here ?
peterwkc
How to alter the a snd value in a list of tuple ? [("rer", 100), ("peter", 23), ("asd", 234)]The value of 100 is need to add another 100. Please help. Thanks.
peterwkc
I need to search through the list of tuple and alter the second value ? Please help. Thanks.
peterwkc