我正在研究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
答案 0 :(得分:4)
由于您要使用writeText
,因此您需要将[FilePath]
转换为Text
。幸运的是,Text
是Monoid
的一个实例,列表是Foldable
的一个实例,因此我们只需使用foldMap pack filenames
来获取单个文本:
-- import Data.Foldable (foldMap)
-- import Data.Text (pack, Text)
toText :: [FilePath] -> Text
toText = foldMap pack
请注意,您需要使用liftIO
在IO a
中实际使用Snap b
,因为Snap
是MonadIO
的实例:
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]
列表展平为单个字符串。我想你知道怎么做。