2014-08-29 78 views
0

我正在研究this project,以便與Haskell相處融洽,並努力尋找簡單的示例。將IO [FilePath]轉換爲字符串或字節流

在這個例子中,我想爲Snap創建一個Web請求處理程序,它會返回一個目錄中的文件列表。

我相信我試圖將getDirectoryContents返回到Snap想要的字節串。

我最困惑什麼用的返回值我在下面的一行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 
+1

也可以完全跳過字符串,並使用高質量的posix-paths庫,它使用嚴格的ByteString作爲文件名,等等http://hackage.haskell.org/package/posix- path-0.2.0.3/docs/System-Posix-Directory-Traversals.html – Michael 2014-08-30 19:00:21

回答

4

既然你想使用writeText,你需要[FilePath]轉換爲Text。幸運的是,TextMonoid一個實例,一個列表是一個Foldable實例,所以我們可以簡單地使用foldMap pack filenames得到一個單一的文本:

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

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

請注意,您需要使用liftIO實際使用IO aSnap b,因爲SnapMonadIO一個實例:

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

如果希望每個FilePath後添加一個換行符(或<br/>),加flip snoc '\n'

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

感謝您提供基於問題上下文的其他內容的全面示例和建議。我確實也需要導入'import Control.Monad.IO.Class'來使liftIO正常工作。 – 2014-08-30 00:35:20

+0

*並且無法滿足snoc的依賴關係,所以現在將其保留爲一個大字符串 – 2014-08-30 00:36:03

+1

@LeonStafford:是的,我忘記了'liftIO'的導入。你需要修改'import Data.Text'來導入'snoc':'import Data.Text(Text,pack,snoc)'。哦,雖然我們處於這種狀態,並且您顯然是Haskell的新手,但請查看[Typeclassopedia](http://www.haskell.org/haskellwiki/Typeclassopedia)。如果你第一次不明白所有事情,不要擔心,但是當你遇到「新」標準類('Traversable','Foldable','Monoid','Applicative')時記住它。 – Zeta 2014-08-30 00:37:25

2

您不能將IO操作「轉換」爲字符串。當然不是,這在概念上是完全不同的。你可以做的是提取/「聚焦」monad中的值,如IO。這就是do塊中val <- action語法的用法,您非常正確。

當前實現的唯一問題是,您有一個IO-單步操作,但想要在單步執行Snap單元中執行它。嗯,實際上Snap深入IO monad,with a whole lot of extra stuff attached通過monad變壓器。但你總是可以使用Snap,就好像它是IO。對於一大堆monads(所有這些都是通過在IO上疊加變壓器而創建的)都是如此,因此有a dedicated class for "monads that can do IO"

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

另一種更容易的做法是將[FilePath]列表展平爲單個字符串。我想你知道該怎麼做。

+0

重新將文件路徑展平爲一個單一的字符串 - 我和Haskell中的其他東西一樣不起眼:P假設[this](http://hackage.haskell.org/package/mime-string-0.2/docs/Codec-MIME -String-Flatten.html)一個? – 2014-08-30 00:23:36