0

我对 Haskell 的 IO 有点陌生,虽然我通读了很多,但我的代码仍然无法工作。

我希望应用程序做什么:

  1. 读取文件的所有行(file1.txt、file2.txt、...),其中每行都包含数字(浮动,如 1.12345)
  2. 对所有这些行进行排序(字符串排序或浮点排序无关紧要,我认为字符串排序更快?)
  3. 获取列表的中间元素并打印出来

这是我到目前为止的代码。我可以保证在传递 [String] 时函数“中间”可以正常工作。

middle :: [a] -> a
middle xs = (drop ((l - 1) `div ` 2) xs) !! 0
            where l = length xs

getSortedMiddleElement :: Int -> String
getSortedMiddleElement i = do
    dat <- readFile $ "file" ++ (show i) ++ ".txt"
    return $ middle $ sort $ lines dat

我从“Int -> Content”函数(我使用 Yesod)调用 getSortedMiddleElement,其中数字通过 URL 传递,中间元素应返回给用户。要从字符串中获取内容,它需要是“字符串”,而不是“IO 字符串”……这怎么能轻松实现?

提前致谢!

4

1 回答 1

5

您的类型签名表明您的函数是纯函数(即,它接受一个 Int 并返回一个字符串)但在内部,您正在执行 IO!Haskell 不会让你编写这样的函数。您从文件中读取的任何内容都会永远停留在 IO monad 中,就是这样(当然,不安全的函数除外)。

在这种情况下,结果并不是那么糟糕,因为 Yesod 是一个高度基于 IO 的框架。所有网络流量也都卡在 IO monad 中!

当您在 monad 转换器堆栈中时,您可以在堆栈的每个级别访问 monadic 计算,但只能直接访问其中一个。您用于lift将计算从 monad 在堆栈中向下移动一层到转换后的 monad。如果IO在堆栈中,无论向下多少层,您都可以直接通过liftIO.

所以如果你有type T = ReaderT String IO那么你可能有一个功能foo :: Int -> T String。在此函数中,您将在 monad 中进行操作,它将使用monad 功能T转换monad。在这种情况下,你可以说,而不是得到一个结果,你会得到一个结果!不过,这只是类型中的一个包装,所以不要认为我们做了任何棘手的事情,比如逃离monad。这可能有点令人困惑,所以让我们看一个例子:IOReaderlift readFileIO StringT StringIO StringReaderTIO

import Control.Monad.Reader (ReaderT)
import Control.Monad.Writer (WriterT)
import Control.Monad.Trans  (lift, liftIO)

type T = ReaderT String IO
getSortedMiddleElement :: Int -> IO String

foo :: Int -> T String
foo n = do
  str <- lift $ getSortedMiddleElement n --str holds a pure String now
  lift $ putStrLn str                    --get `putStrLn` from IO and pass the String
  return str                             --let's wrap it back in T now

但是如果我们离 IO 不止一层怎么办?让我们试一试:

type W = WriterT String T -- WriterT String (ReaderT String IO)

-- This doesn't work; lift only gives you access to the next layer's actions
-- but IO is now more than one layer away!
--
--bar n = do
--  str <- lift $ getSortedMiddleElement n

-- Instead, we need liftIO, which will access IO across many transformer layers
bar :: Int -> W String
bar n = do
  str <- liftIO $ getSortedMiddleElement n
  liftIO $ putStrLn str
  return str
于 2013-08-26T01:49:21.983 回答