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

Squ*_*dly 5 string io parsing haskell

我正在使用控制台从中读取值readLn.

我想写一个函数:

requestValue :: String -> IO a  
requestValue s = do  
  putStrLn $ "Please enter a new value for " ++ s   
  readLn
Run Code Online (Sandbox Code Playgroud)

然后,我可以这样做,例如,

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'}
Run Code Online (Sandbox Code Playgroud)

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

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

Don*_*art 4

由于您想read为用户名添加自己的自定义行为,因此方法是实际为读数名称编写一个新实例。为此,我们可以为名称创建一个新类型:

import Control.Arrow (first)

newtype Name = Name { unName :: String }
    deriving (Eq, Ord, Show)
Run Code Online (Sandbox Code Playgroud)

read并为其编写自定义:

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

这与字符串的读取实例相同,但我们在读入字符串后首先引用该字符串。

现在您可以修改您的Person类型来Name代替String

data Person = Person { age :: Int
                     , name :: Name } deriving Show  
Run Code Online (Sandbox Code Playgroud)

我们正在做生意:

*Main> changeName (Person 31 (Name "dons"))
Please enter a new value for name
Don
Person {age = 31, name = Name {unName = "Don"}}
Run Code Online (Sandbox Code Playgroud)