Haskell IO String -> List

3

大家好,我需要帮助,如何使用sum内置函数从文件中汇总列表?

例如: text.txt 包含 [1,2,3,4]

我想从文件中获取这个列表,并使用sum内置函数汇总这些数字。这可能吗?

谢谢!


1
请参阅haskell+io标签下的常见问题解答。 - Don Stewart
3个回答

3
所以,您将无法实际获得值:: [Int],因为那是不安全的。但我们可以让您获得IO [Int],然后通过>>=传递到print中:
main = (sum . read) `fmap` readFile "myFile" >>= print

如果您正在使用Control.Applicative,您可以让代码更加优美:
main = sum . read <$> readFile "myFile" >>= print

看到了吗!如您所见,这种方式比使用 do 表示法更为简洁。虽然使用 do 表示法可以消除嵌套的 Lambda,但在许多情况下其实并非必需。

编辑:@augustss 提供了以下更优秀的替代方案:

main = print . sum . read =<< readFile "myFile"

这很棒,因为它更简单,不依赖于 Control.Applicative; 更重要的是,它不必像 @hammar 指出的那样被“倒着读”。


@augustss 哇,这好多了!谢谢。 - Jonathan Sterling
这样阅读起来更舒适,从右到左,而在应用程序中却需要“从里到外”阅读。 - hammar

2
当然可以。
main = do
    contents <- readFile "text.txt"
    print . sum . read $ contents

这里使用了Prelude中的一些标准函数:

  • readFile :: FilePath -> IO String 读取文件并返回一个字符串。

  • read :: Read a => String -> aString转换为任何Read类型类中的类型。如果编译器无法确定所需类型,则可能需要添加类型注释。在此示例中,由于我们对结果使用了sum,因此编译器可以推断出a必须是[Integer]。(实际上它推断出的是Num a => [a],但由于类型默认值的缘故,默认为[Integer])。

    read期望与同一类型上show生成的格式相同。

请注意,我必须使用do-notation从IO String中提取String以便将其应用于read


1
从技术上讲,编译器会猜测你想要的类型(通过使用默认值),因为sum可以操作多种数值类型。 - Robin Green

2
如果列表始终以这种格式存在,您需要使用read函数。该函数反序列化数据,即将字符串转换为程序数据类型。例如,
Prelude> read "[1, 2, 3, 4]" :: [Int]
[1,2,3,4]

现在,您可以将其与文件IO结合使用,但如果您不熟悉单子(Monads),则需要阅读一些好的资源,例如[http://www.haskell.org/haskellwiki/Monad]和维基百科。本质上,每个单子都代表了顺序执行中的一步--这是必要的,因为IO修改了环境,因此必须确定其执行顺序。

我想出来的用于读取和求和的代码是:

main = do
    fc <- readFile "file1"
    parsed <- return (read fc :: [Int])
    putStrLn (printf "sum: %d" (sum parsed))

谢谢,虽然它不太好,但它不理解没有方括号"[]"包围的空格分隔的数字。 - Alehar
1
@Alehar 如果你没有大括号,你可以尝试使用words函数,然后去掉末尾的逗号。如果你需要更高级的功能,你可以尝试使用Parsec解析器。 - gatoatigrado

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接