2012-04-20 18 views
2

這工作:爲什麼這個函數組合是非法的

c <- fmap lines (readFile "d:\\tmp\\h.txt") 
let h = map (read :: String -> Int) c 

而這兩條線的 「疊加」 那些無法編譯

fmap (read :: String -> Int) $ fmap lines (readFile "d:\\tmp\\h.txt")

它產生錯誤:

 
interactive:1:36: 
    Couldn't match expected type `Char' with actual type `[Char]' 
    Expected type: String -> String 
     Actual type: String -> [String] 
    In the first argument of `fmap', namely `lines' 
    In the second argument of `($)', namely 
     `fmap lines (readFile "d:\\tmp\\h.txt") 

爲什麼它不能編譯以及如何在一行中完成此操作?我要的是實現的Python簡單

[int(i) for i in open("d:\\tmp\\h.txt")] 

回答

10

你離開map出你的 「疊加」 的(組成):

h <- fmap (map (read :: String -> Int)) $ fmap lines (readFile "d:\\tmp\\h.txt") 

可以簡化到

h <- fmap (map (read :: String -> Int) . lines) (readFile "d:\\tmp\\h.txt") 

如果您在源文件的頂部放置import Control.Applicative行(或者如果您使用ghci以交互方式輸入:m +Control.Applicative),則可以使用<$>運營商而不是fmap,以使其看起來更清潔。 (他們做同樣的事情,他們只是拼寫不同)。

h <- map (read :: String -> Int) . lines <$> readFile "d:\\tmp\\h.txt" 

最後,如果你確實需要的類型簽名,你會發現它看起來在該行的末尾更清晰。

h <- map read . lines <$> readFile "d:\\tmp\\h.txt" :: IO [Int] 
+0

此外,我d將'read'移動到/ let綁定的位置,'fmap(map readInt。lines)$ readFile「foo」'是更可讀的IMO。 – 2012-04-20 15:52:34

9
[int(i) for i in open("d:\\tmp\\h.txt")] 

保持計算從行爲中分離:

return . map read . lines =<< readFile "d:\\tmp\\h.txt" 
+0

我腦中的hlint看到'foo >> = return。酒吧「,並告訴我將其轉換爲」酒吧<$> foo' – 2012-04-21 16:26:03

8

重。你的第二個問題:使用Applicative會使其更易於閱讀:

map read . lines <$> readFile "file" 

您可能能夠避免給read一個類型簽名,這取決於你的代碼的其餘部分,這將是最好

+1

n.b. OP需要'導入Control.Applicative'來使用'<$>'操作符。 – dave4420 2012-04-20 16:55:57

相關問題