2011-05-14 55 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