在Haskell中解析Graph Dimacs格式的直觉

时间:2018-02-13 10:07:45

标签: haskell io

我是Haskell的初学者,我正在努力学习几个小册子,所以我会倾听你的帮助。我读了几本书和指南,但我无法理解如何使用IO操作。我正在尝试以this格式解析文件并创建图形对象。到目前为止,我有这个代码:(节点由正整数标识)

data Edge = Edge Int Int deriving(Show)

data Graph = Graph {
                nodeCount :: Int,
                edges :: [Edge]
            }   deriving (Show)     

parseInput :: String -> IO ()
parseInput filePath = do
    handle <- openFile filePath ReadMode
    contents <- hGetContents handle
    putStrLn contents
    hClose handle

我明白haskell是懒惰的。我想创建带签名的功能

parseInput :: String -> Maybe Graph

所以我在错误或图表上得到Nothing。我的问题是我不能简单地读取文件并在一个函数中创建图形。据我所知,我应该得到IO String,创建对象,然后使用句柄关闭文件?有人能指出我正确的方向吗?我对此很难,因为它与命令式语言非常不同。

感谢您的任何建议。

1 个答案:

答案 0 :(得分:1)

您可以将其视为两个不同的世界:

  • 确定性的,普通世界,所有纯函数都存在,
  • 神奇的IO世界 文件在哪里,你真的不知道会发生什么。

当有人说IO是一个monad时,你可以理解它:你可以做任何神奇的IO事情,但是一旦施放了法术,就没有办法回到平凡状态。

因此,IO类型的函数是你的法术,而parseInput是一个普通的,完全可预测的机械装置:对于任何给定的输入,你可能总是知道输出是什么。一旦你掌握了技巧,你必须召唤一些contentsreadFile,然后将你的普通函数移动到神奇的IO世界以及{{1} }:

fmap

到目前为止,您可以应用解析器:

parseInput :: String -> Maybe Graph
parseInput = ...

magicallyGetContents :: IO String
magicallyGetContents = readFile ...

parseMagicalInput :: IO String -> IO (Maybe Graph)
parseMagicalInput = fmap parseInput

你可以使用几种法术来帮助你进入神奇的一面。最简单的是:

λ :t parseInput magicallyGetContents
    -- This won't work because of the interworld barrier.

<interactive>... error:
    • Couldn't match type ...
      Expected type: String
        Actual type: IO String
...

λ :t parseMagicalInput magicallyGetContents
    -- This is fine, because both things are on the magical side.
parseMagicalInput  magicallyGetContents :: IO (Maybe Graph)

(这个名字暗示着神奇的世界实际上是哈斯克尔所有事物的家园。)

请注意,一旦你应用了这个相当简单的法术,就无法回头了。虽然理论上你可以通过RAM破解并检索字节,但这并不简单。例如,这不会:

return :: a -> IO a

所以,你的方法是假设你拥有纯净世界中的内容,并构建你的机器然后工作,然后穿过它的interworld障碍并将其应用于任何数量的DIMACS另一边有图形文件。

快乐的冒险!

p.s。您还可以查看this answer以获得更实际的观点。