2012-05-22 27 views
3

有時,當我想用​​wget,我剛剛結束了打印一堆線與Python像這樣:如何在Haskell中表示這個Python for循環?

>>> for i in range(25): 
... print "http://www.theoi.com/Text/HomerOdyssey", i, ".html" 
... 
http://www.theoi.com/Text/HomerOdyssey 0 .html 
http://www.theoi.com/Text/HomerOdyssey 1 .html 
http://www.theoi.com/Text/HomerOdyssey 2 .html 
http://www.theoi.com/Text/HomerOdyssey 3 .html 
http://www.theoi.com/Text/HomerOdyssey 4 .html 
http://www.theoi.com/Text/HomerOdyssey 5 .html 
http://www.theoi.com/Text/HomerOdyssey 6 .html 
http://www.theoi.com/Text/HomerOdyssey 7 .html 
http://www.theoi.com/Text/HomerOdyssey 8 .html 
http://www.theoi.com/Text/HomerOdyssey 9 .html 
http://www.theoi.com/Text/HomerOdyssey 10 .html 
http://www.theoi.com/Text/HomerOdyssey 11 .html 
http://www.theoi.com/Text/HomerOdyssey 12 .html 
http://www.theoi.com/Text/HomerOdyssey 13 .html 
http://www.theoi.com/Text/HomerOdyssey 14 .html 
http://www.theoi.com/Text/HomerOdyssey 15 .html 
http://www.theoi.com/Text/HomerOdyssey 16 .html 
http://www.theoi.com/Text/HomerOdyssey 17 .html 
http://www.theoi.com/Text/HomerOdyssey 18 .html 
http://www.theoi.com/Text/HomerOdyssey 19 .html 
http://www.theoi.com/Text/HomerOdyssey 20 .html 
http://www.theoi.com/Text/HomerOdyssey 21 .html 
http://www.theoi.com/Text/HomerOdyssey 22 .html 
http://www.theoi.com/Text/HomerOdyssey 23 .html 
http://www.theoi.com/Text/HomerOdyssey 24 .html 
>>> 

我可以粘貼輸出到一個新的文件,刪除空格,並使用wget -i

但是我厭倦了Python。

我想學習Haskell。

儘管花了10分鐘試圖從ghci做同樣的事情,我沒有進一步前進。

這是我的嘗試看起來像:

[email protected]:~/oldio$ ghci 
GHCi, version 7.0.4: http://www.haskell.org/ghc/ :? for help 
Loading package ghc-prim ... linking ... done. 
Loading package integer-gmp ... linking ... done. 
Loading package base ... linking ... done. 
Prelude> putStrLn 

<interactive>:1:1: 
    No instance for (Show (String -> IO())) 
     arising from a use of `print' 
    Possible fix: 
     add an instance declaration for (Show (String -> IO())) 
    In a stmt of an interactive GHCi command: print it 
Prelude> putStrLn "hey" 
hey 
Prelude> putStrLn "hey" [1..10] 

<interactive>:1:1: 
    The function `putStrLn' is applied to two arguments, 
    but its type `String -> IO()' has only one 
    In the expression: putStrLn "hey" [1 .. 10] 
    In an equation for `it': it = putStrLn "hey" [1 .. 10] 
Prelude> putStrLn "hey" snd [1..10] 

<interactive>:1:1: 
    The function `putStrLn' is applied to three arguments, 
    but its type `String -> IO()' has only one 
    In the expression: putStrLn "hey" snd [1 .. 10] 
    In an equation for `it': it = putStrLn "hey" snd [1 .. 10] 
Prelude> putStrLn "hey" $ snd [1..10] 

<interactive>:1:1: 
    The first argument of ($) takes one argument, 
    but its type `IO()' has none 
    In the expression: putStrLn "hey" $ snd [1 .. 10] 
    In an equation for `it': it = putStrLn "hey" $ snd [1 .. 10] 
Prelude> "hello" 
"hello" 
Prelude> "hello" ++ "world" 
"helloworld" 
Prelude> "hello" ++ [1..10] ++ " world" 

<interactive>:1:16: 
    No instance for (Num Char) 
     arising from the literal `10' 
    Possible fix: add an instance declaration for (Num Char) 
    In the expression: 10 
    In the first argument of `(++)', namely `[1 .. 10]' 
    In the second argument of `(++)', namely `[1 .. 10] ++ " world"' 
Prelude> "hello" ++ print [1..10] ++ " world" 

<interactive>:1:12: 
    Couldn't match expected type `[Char]' with actual type `IO()' 
    In the return type of a call of `print' 
    In the first argument of `(++)', namely `print [1 .. 10]' 
    In the second argument of `(++)', namely 
     `print [1 .. 10] ++ " world"' 
Prelude> print [1..10] 
[1,2,3,4,5,6,7,8,9,10] 
Prelude> map ("hello") [1..10] 

<interactive>:1:6: 
    Couldn't match expected type `a0 -> b0' with actual type `[Char]' 
    In the first argument of `map', namely `("hello")' 
    In the expression: map ("hello") [1 .. 10] 
    In an equation for `it': it = map ("hello") [1 .. 10] 
Prelude> greeting :: String --> Int -> [String, Int] 

<interactive>:1:39: parse error on input `,' 
Prelude> greeting :: String --> Int -> [(String), (Int)] 

<interactive>:1:41: parse error on input `,' 
Prelude> greeting :: String -> Int -> [(String), (Int)] 

<interactive>:1:40: parse error on input `,' 
Prelude> greeting :: String -> Int -> [(String) (Int)] 

<interactive>:1:1: Not in scope: `greeting' 
Prelude> foreach [1..24] print 

<interactive>:1:1: Not in scope: `foreach' 
Prelude> import Data.IORef 
Prelude Data.IORef> foreach [1..24] print 

<interactive>:1:1: Not in scope: `foreach' 
Prelude Data.IORef> foreach = flip mapM_ 

<interactive>:1:9: parse error on input `=' 
+2

正如你所發現的,Haskell I/O不是一個10分鐘的話題... –

+1

@sacundim'putStrLn「hey」'vs'putStrLn「hey」[1..10]'不是IO問題 - 他還沒有掌握控制結構。 –

+2

請注意,您的示例是相當差的Python風格。 – Marcin

回答

9
mapM_ (\i -> putStrLn (concat ["http://www.theoi.com/Text/HomerOdyssey", show i, ".html"])) [0..24] 

作爲獎勵,這不打印任何空格。

現在一些理論:

  • putStrLn是一個函數,它接受一個單一參數。 Python,Perl等會吸取你給print的所有參數,並把它變成一個單一的字符串。在Haskell中,你必須自己做。
  • mapM_需要兩個參數。第二個列表,第一個函數,它依次傳遞列表中的每個元素。我們在這裏傳遞的函數是一個匿名函數(就像Python中的lambda)。
13
for i in range(25): 
... print "http://www.theoi.com/Text/HomerOdyssey", i, ".html" 

變爲:

進口Control.Monad

,使我們可以:

forM_ [1..25] $ \i -> 
    putStrLn $ "http://www.theoi.com/Text/HomerOdyssey" ++ show i ++ ".html" 
+0

這可能有助於解釋'$'是什麼。 – Marcin

+0

@Marcin http://stackoverflow.com/questions/940382/haskell-difference-between-dot-and-dollar-sign和http://stackoverflow.com/questions/3030675/haskell-function-composition-andfunction -application-idioms-correct-us –

+0

它可能有助於在你的答案中解釋它。 – Marcin

3

考慮使用列表理解:

mapM_ putStrLn ["http://www.theoi.com/Text/HomerOdyssey" ++ show i ++ ".html" | i <- [0..24]] 
1

這不完全是一個答案,但它太長的評論。我認爲關於ghci的幾句話將會有很大的幫助。

在ghci中,您可以分別使用:t:info來顯示某些內容的類型和相關信息。

Prelude> :t putStrLn 
putStrLn :: String -> IO() 
Prelude> :info putStrLn 
putStrLn :: String -> IO()  -- Defined in `System.IO' 
Prelude> :t putStrLn "Hello, World" 
putStrLn "Hello, World" :: IO() 

:t是有用的,因爲你可以用它來顯示任意表達式的類型,這:info不會。但是:info可以提供有關的東西,沒有類型,如類型本身或類型構造信息:

Prelude> :info IO 
newtype IO a 
    = GHC.Types.IO (GHC.Prim.State# GHC.Prim.RealWorld 
        -> (# GHC.Prim.State# GHC.Prim.RealWorld, a #)) 
    -- Defined in `GHC.Types' 
instance Monad IO -- Defined in `GHC.Base' 
instance Functor IO -- Defined in `GHC.Base' 

當你試圖找出如何讓ghci中接受的東西,:t是非常有用的。

接下來,認識到ghci提示可以爲您提供一行一行的do-notation,在IO中。如果您輸入IO x類型的東西,那麼當您按下回車鍵時將會評估該語句。如果你想綁定那個x,使用do-notation箭頭。如果要創建新綁定(即創建新功能或標識符),請使用let。如果你輸入一個不是IO的表達式,ghci將嘗試給你show,如果沒有定義Show實例,這將不起作用。

Prelude> putStrLn "Hello, World" 
Hello, World 
Prelude> :t getChar 
getChar :: IO Char 
Prelude> x <- getChar 
yPrelude> 
Prelude> show x 
"'y'" 
Prelude> let g = 10 :: Int 
Prelude> :t g 
g :: Int 
Prelude> show g 
"10" 
Prelude> g 
10 

注意show gg是不一樣的。你或許可以從上面概述的行爲中找出原因。

+0

這是非常有幫助的。謝謝! – magnetar