haskell-problem:io string - > [INT]

时间:2011-02-23 12:16:18

标签: string haskell io int

你好伟大的程序员,

我正在使用haskell的第一步,并且有一个令我困惑的功能:

import Data.List.Split
getncheck_guesslist = do
    line <- getLine
    let tmp = splitOneOf ",;" line
    map read tmp::[Int]

splitOneOf在Data.List.Split中(我用cabal安装拆分安装它) splitOneOf :: (Eq a)=> [a]->[a]->[[a]]

从错误中我得知有一些类型不正确 - 但不知道如何解决这些冲突,因为 IO 对我来说仍然是个谜。

我想读取用逗号或分号分隔的整数输入,并得到一个整数列表,所以:

  • 如何检查用户输入是否为Int
  • 类型
  • 如何将“IO String”类型的输入“转换”为[Int]

提前感谢您的想法和提示   - 你的ε/ 2

4 个答案:

答案 0 :(得分:12)

当你编写一个使用IO monad的函数时,你想从函数返回的任何值也必须在IO monad中。

这意味着,您必须返回类型为[Int]的内容,而不是返回类型为IO [Int]的值。要执行此操作,请使用return函数,该函数将值“包装”到IO(它实际上适用于任何 monad)。

只需更改最后一行,即可使用return包装您的值,如下所示:

getncheck_guesslist = do
    line <- getLine
    let tmp = splitOneOf ",;" line
    return (map read tmp :: [Int])

答案 1 :(得分:7)

在Haskell中执行此操作的“正确方法”是将IO与其他所有内容分开。您的代码的直接翻译将是:

getncheck_guesslist :: IO [Int]
getncheck_guesslist = do line <- getLine               -- get
                         return (check_guesslist line) -- check

check_guesslist :: String -> [Int]
check_guesslist line = let tmp = splitOneOf ",;" line
                       in map read tmp

请注意,getncheck_guesslist只是一个IO操作。该函数没有输入参数,即使它确实需要来自getLine(IO)输入

另请注意,getncheck_guesslist是对getLine IO操作的简单修改。是不是有一个组合器可以让我推动一个函数来对monad中的值进行操作?停止。 Hoogle时间!

我有一个函数(a -> b)。我有一个输入类型的值,但它被卡在monad m a中。我想在monad中执行函数,所以结果也不可避免地会被卡在monad m b中。把这些全部放在一起,我们就是(a -> b) -> m a -> m b。瞧,fmap正是我们所寻找的。

get_guesslist = check_guesslist `fmap` getLine
-- or, taking it a step further
get_guesslist = (map read . splitOneOf ",;") `fmap` getLine :: IO [Int]

最后一点,无论何时使用somethingAndSomethingElse这样的名称编写方法,编写和调用somethingsomethingElse作为两个单独的方法通常会有更好的编码风格。对于最终版本,我只是将其重命名为get_guesslist,因为从概念上讲它就是它的作用。它得到了Ints列表的猜测。

作为最后的最后一点,我已经离开了baroap开始的地方。 ;)fmap<$>相同。

答案 2 :(得分:2)

如果某些内容属于IO monad,则无法将其带到纯粹的外部世界进行进一步处理。相反,您将纯函数传递给IO中的函数内部。

最后,你的程序会读取一些输入并写入一些输出,因此你的主要功能是使用IO,否则你将无法输出任何内容。而不是阅读IO String并创建[Int],而是将使用该[Int]的函数传递到主函数中,并在do中使用它。

答案 3 :(得分:2)

import Data.List.Split
import Control.Applicative

getncheck_guesslist :: IO [Int]
getncheck_guesslist = map read . splitOneOf ",;" <$> getLine

每次代码陷入foo >>= return . bar时,你都会通过去掉do-block(并纠正类型错误),你没有使用monad的monadic功能,而只使用它的functor部分,直言不讳地说,你没有弄乱类型的IO部分,而是使用a的{​​{1}}:

IO a

(<$>) :: (Functor f) => (a -> b) -> f a -> f b 将是fmap的非中缀名称。两者都与<$>密切相关。)

上面的代码对于ad-hoc代码来说非常惯用,但干净的代码看起来像

map

,或者,如果您不想忽略非int输入但是错误输出,

import Data.Maybe

maybeRead :: Read a => String -> Maybe a
maybeRead = fmap fst . listToMaybe . reads 
                               -- That fmap is using "instance Functor Maybe"

parseGuessList :: String -> [Int]
parseGuessList =  catMaybes . map maybeRead . splitOneOf ",;"

getncheck_guesslist = parseGuessList <$> getLine

(但要注意,我只证明代码是正确的,而不是实际尝试过。)

如果它比你想要使用正确的解析库更复杂,我想。