将IO [FilePath]转换为String或Bytestream

时间:2014-08-29 23:59:03

标签: haskell haskell-snap-framework

我正在研究this project与Haskell的关系并努力寻找简单的例子。

在这个例子中,我希望有一个Snap的Web请求处理程序,它返回一个目录中的文件列表。

我相信我正试图将getDirectoryContents返回到Snap想要的Bytestring。

我最担心的是如何处理下面第filenames <- getDirectoryContents "data"行的返回值:

import Control.Applicative
import Snap.Core
import Snap.Util.FileServe
import Snap.Http.Server
import System.Directory (getDirectoryContents)

main :: IO ()
main = quickHttpServe site

site :: Snap ()
site =
    ifTop (writeBS "hello world") <|> 
    route [ ("foo", writeBS "bar")
          , ("echo/:echoparam", echoHandler)
          , ("view_root_json_files", listRootFilesHandler)
          ] <|> 
    dir "static" (serveDirectory ".")

echoHandler :: Snap ()
echoHandler = do
    param <- getParam "echoparam"
    maybe (writeBS "must specify echo/param in URL")
          writeBS param

listRootFilesHandler :: Snap ()
listRootFilesHandler = do
    -- read all filenames in /data folders
    filenames <- getDirectoryContents "data"
    writeText filenames

2 个答案:

答案 0 :(得分:4)

由于您要使用writeText,因此您需要将[FilePath]转换为Text。幸运的是,TextMonoid的一个实例,列表是Foldable的一个实例,因此我们只需使用foldMap pack filenames来获取单个文本:

-- import Data.Foldable (foldMap)
-- import Data.Text (pack, Text)

toText :: [FilePath] -> Text
toText = foldMap pack

请注意,您需要使用liftIOIO a中实际使用Snap b,因为SnapMonadIO的实例:

listRootFilesHandler :: Snap ()
listRootFilesHandler = do
    filenames <- liftIO $ getDirectoryContents "data"
    writeText $ toText filenames

如果您想在每个<br/>后添加换行符(或FilePath),请添加flip snoc '\n'

toText = foldMap (flip snoc '\n' . pack)
-- toText = foldMap (flip append (pack "<br/>") . pack)

答案 1 :(得分:2)

你不能&#34;转换&#34;对字符串的IO操作。当然不是,从概念上讲,它是完全不同的东西。你可以做的是提取/&#34;焦点&#34; monad中的值,例如IO。这就是val <- action块中do语法的用法,你有完全正确的。

您当前实现的唯一问题是您有IO - monad操作,但想要在Snap monad中执行它。好吧,实际上Snap 深入IO monad,with a whole lot of extra stuff attached来自monad变换器。但您可以始终使用Snap,就好像它是IO一样。这对于一大堆monad来说都是如此(所有这些都是通过在IO上堆叠变换器而创建的),所以a dedicated class for "monads that can do IO"已经存在。

listRootFilesHandler = do
    -- read all filenames in /data folders
    filenames <- liftIO $ getDirectoryContents "data"
    ...

另一个相当容易的事情是将[FilePath]列表展平为单个字符串。我想你知道怎么做。