阅读文件的行,排序并返回中间元素
我对Haskell的IO有点新,虽然我经常阅读它,但我的代码仍然无法工作。阅读文件的行,排序并返回中间元素
我希望应用程序做什么:
- 读取文件的所有行(FILE1.TXT,FILE2.TXT,...),其中都含有数字在每行(浮像1.12345)
- 排序所有这些行(字符串排序或浮动的排序并不重要,我想串排序是更快?)
- 获取列表的中间元素,并打印出来
这是我的代码到目前为止。我可以保证函数“middle”在传递[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
我从一个“内部 - >内容”,呼吁getSortedMiddleElement功能(我用耶索德),其中数字正在通过URL传递和中间元素应该返回给用户。为了让内容脱离字符串,它需要是“字符串”,而不是“IO字符串”......如何轻松实现?
在此先感谢!
您的类型签名表示您的函数是纯的(即它需要一个Int并返回一个String),但在里面,您正在执行IO! Haskell不会让你编写这样的函数。你从文件中读取的任何内容都会永久卡在IO monad中,这就是(当然,除了不安全的函数)。
在这种情况下,结果并不那么糟糕,因为Yesod是一个严重的基于IO的框架。所有的网络流量都停留在IO monad中!
当你在一个monad变压器堆栈中时,你可以在堆栈的每个级别访问monadic计算,但只有其中一个直接。您可以使用lift
将计算从堆栈中的单层移动到已转换的monad。如果IO
位于堆栈中,无论层数有多少,都可以通过liftIO
直接访问其操作。
所以,如果你有type T = ReaderT String IO
那么你可能有一个功能foo :: Int -> T String
。在此函数中,您将在T
monad中操作,它将IO
monad与Reader
monad功能进行转换。在这种情况下,您可以说lift readFile
,而不是获得IO String
结果,您将得到T String
结果!这只是IO String
包装的ReaderT
类型,所以不要认为我们做了任何棘手的事情,比如逃脱IO
monad。这可能是一个有点混乱,所以让我们来看一个例子:
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
非常感谢这个详细的答案!'LiftIO'正是我所需要的。 – sibbl
一种可能性是将类型更改为“Int - > IO String”,然后像处理该函数一样处理,例如, 'readFile'或任何其他IO功能。 – kqr
谢谢,这听起来不错!我该如何处理'getTestR :: Int - > Handler RepPlain',它会返回HTTP响应?'getTestR :: Int - > IO Handler RepPlain'不起作用:( – sibbl
我希望我可以告诉你,但我绝不是Yesod的专家。:( – kqr