如何在不是双引号的字符串上使用read?

时间:2011-05-14 20:18:26

标签: string parsing haskell io

我正在使用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'}

我遇到的问题是String的读取实例似乎要求字符串在引号中。当我真的只想输入"Fred"时,我不想在控制台中输入Fred来更改名称。

是否有一种简单的方法可以保持requestValue多态?

2 个答案:

答案 0 :(得分: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 :(得分:2)

您需要getLine,而不是readLn