2010-06-18 41 views
2

這個問題這裏是有關 Haskell Input Return Tuple哈斯克爾IO傳遞到另一個功能

我不知道我們怎樣才能通過從單子IO另一個函數的輸入,以便做一些計算。

其實我想要的是像

-- 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 

在第二個例子中,maxinvestinput從文件中讀取數據轉換爲maximuminvest期望的類型。 請幫忙。

謝謝。

回答

8

首先,我認爲你對理解Haskell有一些基本的問題,所以讓我們一步一步地構建。希望你會發現這有幫助。其中一些將會到達你所擁有的代碼,而其中的一些則不會,但是這是我寫這段代碼時會想到的一個緩慢版本。之後,我會試着回答你的一個特定問題。


我不太清楚你想讓你的程序做什麼。據我所知,你需要一個程序來讀取一個包含人員和他們投資清單的文件。不過,我不確定你想用它做什麼。你似乎(a)想要一個明智的數據結構([(String,Integer)]),但然後(b)只使用整數,所以我會假設你也想對這些字符串做些什麼。我們來看看這個。首先,你需要一個函數,給定一個整數列表,返回最大值。你把這個叫做maximuminvest,但是這個功能比較一般,只是投資,所以爲什麼不叫它maximum?事實證明,這個功能已經存在。你怎麼能知道這個?我推薦Hoogle-它是一個Haskell搜索引擎,可以讓你搜索函數名和類型。你需要一個從整數列表到單個整數的函數,所以讓我們search for that。事實證明,第一個結果是maximum,這是你想要的更一般的版本。但爲了學習的目的,假設你想自己寫;在這種情況下,你的實現就好了。

好的,現在我們可以計算出最大值。但首先,我們需要構建我們的列表。我們將需要[String] -> [(String,Integer)]類型的函數來將我們的無格式列表轉換爲合理的列表。那麼,要從字符串中獲取整數,我們需要使用read。長話短說,你目前的實施情況也很好,但我會(a)爲單項目清單添加一個error案例(或者,如果我感覺不錯,只需要返回一個空列表來忽略最終項目奇數長度列表),和(b)中使用大寫字母的名稱,這樣我就可以分辨的話(而且可能是一個不同的名稱):

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

現在TAT我們有了這些,我們可以提供我們自己有一個便利的功能,maxInvestment :: [String] -> Integer。唯一缺少的是從tupled列表到整數列表的能力。有幾種方法可以解決這個問題。一個是你擁有的,儘管這在Haskell中是不尋常的。第二個將是使用map :: (a -> b) -> [a] -> [b]。這是一個將函數應用於列表的每個元素的函數。因此,您的getint相當於更簡單的map snd。最好的方式可能是使用Data.List.maximumBy :: :: (a -> a -> Ordering) -> [a] -> a。這就像maximum,但它允許你使用你自己的比較功能。並且使用Data.Ord.comparing :: Ord a => (b -> a) -> b -> b -> Ordering,事情變得很好。此功能允許您通過將兩個任意對象轉換爲可比較的東西來比較兩個任意對象。因此,我會寫

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

雖然你也可以寫maxInvestment = maximum . map snd . tupledInvestors

好的,現在進入IO。那麼你的主要功能就是想從特定的文件中讀取數據,計算出最大的投資並將其打印出來。來表示一種方式是作爲一系列的三個不同的步驟:

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

(該$運營商,如果你還沒有看到它,只是功能應用,但更方便的優先級,它的類型是(a -> b) -> a -> b,這將使意義),但let maxInv似乎很沒有意義,所以我們可以擺脫的是:

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

.,如果你還沒有看到它,是函數組合; f . g\x -> f (g x)相同。 (它的型號爲(b -> c) -> (a -> b) -> a -> c,這應該有一些想法是有道理的。)因此,f . g $ h xf (g (h x))相同,只是更容易閱讀。我們能夠擺脫let。那麼<-呢?爲此,我們可以使用=<< :: Monad m => (a -> m b) -> m a -> m b運算符。請注意,它幾乎就像$,但幾乎所有東西都會被m污染。這允許我們取一個單值(在這裏,readFile "C:\\Invest.txt" :: IO String),將它傳遞給一個函數,將一個普通值轉換爲一元值,並獲得該單值。因此,我們有

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

這應該是清楚的,我希望,特別是如果你認爲的=<<作爲一個單子$

我不確定testfile發生了什麼;如果你編輯你的問題以反映這一點,我會嘗試更新我的答案。


還有一件事。你說

我不知道我們如何可以將monad IO的輸入傳遞給另一個函數,以便做一些計算。

與Haskell中的所有內容一樣,這是類型的問題。所以讓我們通過這裏的類型來解謎。你有一些功能f :: a -> b和一些monadic值m :: IO a。您想使用f來獲得b類型的值。這是不可能的,正如我在my answer to your other question中解釋的;然而,你可以得到IO b類型的東西。因此,你需要一個功能,它需要你的f,並給你一個monadic版本。換句話說,類型爲Monad m => (a -> b) -> (m a -> m b)。如果我們plug that into Hoogle,第一個結果是Control.Monad.liftM,它恰好具有該類型簽名。因此,可以治療liftM作爲略有不同的「一元$」比=<<f \ liftM`米applies˚Fto the pure result of(in accordance with whichever monad you're using) and returns the monadic result. The difference is that liftM takes a pure function on the left, and = < <`取的局部一元之一。

另一種方式來寫同樣的事情是do -notation:

do x <- m 
    return $ f x 

這是說「得到xm,適用f它,結果擡回到單子。」這與陳述return . f =<< m相同,這正是liftM。第一個f執行純計算;其結果被傳遞到return(通過.),將純值提升到monad;然後通過=<,將該部分一元函數應用於m

它已經很晚了,所以我不確定它有多少意義。讓我試着總結一下。總之,沒有通用的方式來留下一個monad。當你想對monadic值進行計算時,你可以將純粹的值(包括函數)提升到monad中,而不是;這可能會違反純度,這將是Very Bad™。


我希望實際上回答你的問題。讓我知道如果沒有,所以我可以嘗試使它更有幫助!

+0

爲什麼功能應用程序有類型簽名 (a - > b) - > a - > b? 爲什麼功能組合具有類型簽名 (b→c) - >(a→b)→a→c? 這是什麼=「:: Monad m =>(a - > m b) - > m a - > m b? 除此之外,我也不明白所有在這裏提到的與monad有關的話題? – peterwkc 2010-06-20 03:33:19

+0

如何改變元組列表中的snd值? [(「rer」,100),(「peter」,23),(「asd」,234)] 100的值需要再加100。謝謝。 – peterwkc 2010-06-20 03:43:00

+0

我需要搜索元組列表並更改第二個值? 請幫忙。 謝謝。 – peterwkc 2010-06-20 03:54:03

3

我不知道我理解你的問題,但我會盡我所能回答。如果我理解正確,我已經簡化了一些東西來解決問題的「肉」。

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
+0

我需要創建一個函數,它使用monad接受IO,然後這個用戶輸入的數據被傳遞到另一個函數作爲輸入,如突出顯示在這裏。 maxinvest :: a maxinvest = liftM maximuminvest maxinvestinput – peterwkc 2010-06-18 07:49:19

+1

我不明白你在問什麼。看起來這樣可以回答你的問題,但是你的'maxinvest'的簽名是沒有意義的。它不能是任何類型的'a';它只能是一個特定的類型,即'IO Integer'。它甚至不可能是'IO a',因爲你的其他函數假定有整數。 – 2010-06-18 08:09:42