2013-03-09 88 views
4

我就在Haskell的IO單子的更深層次的運作對他們 wiki讀書了,我碰到這個代碼Haskell的IO例如

main = do a <- ask "What is your name?" 
     b <- ask "How old are you?" 
     return() 
ask s = do putStr s 
     readLn 

這對我來說很有意義來了。 ask函數應該打印出給它的字符串並返回 可以傳遞給a或b的一行。

然而,加載到GHCi我得到的問題。告訴我沒有使用ask的讀取實例,並且我可以導入GHC.Read。這不應該是必要的。這段代碼在Haskell.org上,所以我認爲它應該可以工作。語言中的某些內容是否發生了變化,或者我缺少一些重要的理解?

回答

4

我已經對代碼做了兩處更改。

  1. 修復壓痕 - 記住,Haskell是「太空敏感」,所以請確保代碼看起來正確對齊
  2. 顯式類型簽名。這有點棘手。但是按照經驗法則,當你希望工作的代碼不會。嘗試使用類型對代碼進行註釋,如下所示。你會明白爲什麼這是及時的。

下面是修改後的代碼:

main = do 
    a <- askString "What is your name?" 
    b <- askOther "How old are you?" 

    putStrLn "" 
    putStrLn "Name and age" 
    putStrLn (a :: String) 
    print (b :: Int) 
    return() 

askString s = do 
    putStrLn s 
    getLine 

askOther s = do 
    putStrLn s 
    readLn 

編輯:對不起,該代碼實際上現在編譯。再次,隨着你的haskell成熟,你會明白爲什麼askString和askOther看起來不一樣。下面是一個例子來看:

$ runghc Hello.hs 
What is your name? 
Arash 
How old are you? 
22 

Name and age 
Arash 
22 
+0

不askOther和askStringhave之間的差額作爲一個傳遞一個int和其他通過一個與他們的使用做使ScopedTypeVariables extention串? – 2013-03-09 08:44:24

+1

@RyanCori,'askString :: String - > IO String',但是'askOther ::(Read a)=> String - > IO a'(閱讀missingnos a''可以成爲'Int'的精彩答案)。你也可以使用'askOther' *作爲字符串*,但是程序的用戶必須輸入'「Arash」'而不是簡單的'Arash'。 – Tarrasch 2013-03-09 14:54:21

7

如果創建只是問功能的文件(沒有問題的主),並加載它GHCI,你將能夠看到問的類型是

ask :: (Read a) => String -> IO a 

這意味着它在返回類型中是多態的。

的問題是,當你做

a <- ask "What is your name" 

編譯器需要知道什麼是a類型,以便它可以使用正確的反序列化功能爲你從inpout讀線。但a不在其他地方使用,也沒有任何類型簽名,因此類型推斷不能推斷出a的類型。編譯器放棄並給你那個「ambiguos types」消息。

主要有兩種方法來解決這個問題:

  1. 讓撫功能總是返回相同的類型。您可以通過添加特定的簽名

    ask :: String -> IO String 
    

    或改變readLn弄成getLine做到這一點。

  2. 在您使用多態函數的地方添加類型簽名。您可以一個類型簽名添加到問稱自己:

    a <- ask "What is your name" :: IO String 
    

    ,或者你可以直接將它添加到變量

    (a :: String) <- ask "What is your name" 
    

    然而,這第二個選項沒有被默認Haskell語法允許。你需要通過添加作爲第一行這樣的評論在您的文件

    {-# LANGUAGE ScopedTypeVariables #-}