2011-05-14 51 views
5

我在從控制檯使用readLn讀取值。如何使用不帶雙引號的字符串讀取數據?

我想編寫一個函數:

requestValue :: String -> IO a 
requestValue s = do 
    putStrLn $ "Please enter a new value for " ++ s 
    readLn 

我則是能夠做到的,例如,

changeAge :: Person -> IO Person 
changeAge p = do 
    age' <- requestValue "age" 
    return $ p { age = age'} 

changeName :: Person -> IO Person 
changeName p = do 
    name' <- requestValue "name" 
    return $ p { name = name'} 

我的問題是,字符串的讀取實例似乎需要字符串在引號中。我不希望有在控制檯輸入"Fred"改名字的時候我真的只想在Fred輸入。

是否有一個簡單的方法來做到這一點,保持requestValue多態?

回答

4

既然你想添加自己的自定義read行爲對用戶名,做到這一點的方法是實際寫讀數名稱的新實例。要做到我們可以爲名稱的新類型:

import Control.Arrow (first) 

newtype Name = Name { unName :: String } 
    deriving (Eq, Ord, Show) 

,並編寫自定義read吧:

instance Read Name where 
    readsPrec n = map (first Name) . readsPrec n . quote 
     where quote s = '"' : s ++ ['"'] 

這是相同的字符串讀實例,但我們首先引用字符串,在讀完之後。

現在,你可以修改你Person類型使用Name代替String

data Person = Person { age :: Int 
        , name :: Name } deriving Show 

和我們在業務:

*Main> changeName (Person 31 (Name "dons")) 
Please enter a new value for name 
Don 
Person {age = 31, name = Name {unName = "Don"}} 
+1

你不應該也照顧逃脫引號的字符串? – Peaker 2011-05-14 22:54:03

2

你想getLine,不readLn

+1

不,我不知道。 getLine是'IO String'類型,而readLn是'IO a'。我想requestValue爲類型'字符串 - > IO了',所以我需要readLn,而不是函數getline。 – Squidly 2011-05-14 21:23:25

+0

是的,請看唐的回答。 :) – augustss 2011-05-14 22:35:46

相關問題