打开一个monad

Pau*_*han 5 haskell

鉴于以下计划,我遇到了与monad打交道的问题.

module Main 
where
import System.Environment
import System.Directory
import System.IO
import Text.CSV

--------------------------------------------------

exister :: String -> IO Bool
exister path = do
  fileexist <- doesFileExist path 
  direxist  <- doesDirectoryExist path
  return (fileexist || direxist )

--------------------------------------------------
slurp :: String -> IO String 
slurp path = do
  withFile path ReadMode (\handle -> do
                             contents <- hGetContents handle
                             last contents `seq` return contents )
--------------------------------------------------    
main :: IO ()
main = do
  [csv_filename] <- getArgs
  putStrLn (show csv_filename)
  csv_raw <- slurp csv_filename
  let csv_data = parseCSV csv_filename csv_raw

  printCSV csv_data -- unable to compile. 
Run Code Online (Sandbox Code Playgroud)

csv_data是一种Either(parseerror)CSV类型,而printCSV只接受CSV数据.


这是工作版和破碎版之间的编辑.

***************
*** 27,30 ****
    csv_raw <- slurp csv_filename
    let csv_data = parseCSV csv_filename csv_raw

!   printCSV csv_data -- unable to compile. 
\ No newline at end of file
--- 27,35 ----
    csv_raw <- slurp csv_filename
    let csv_data = parseCSV csv_filename csv_raw

!   case csv_data of 
!     Left error -> putStrLn $ show error
!     Right csv_data -> putStrLn $ printCSV csv_data
!     
!   putStrLn "done"
!       
Run Code Online (Sandbox Code Playgroud)

参考:http://hackage.haskell.org/packages/archive/csv/0.1.2/doc/html/Text-CSV.html

Dan*_*ton 10

关于monads:

是的,Either a是一个单子.所以简化问题,你基本上要求这个:

main = print $ magicMonadUnwrap v

v :: Either String Int
v = Right 3

magicMonadUnwrap :: (Monad m) => m a -> a
magicMonadUnwrap = undefined
Run Code Online (Sandbox Code Playgroud)

你怎么定义magicMonadUnwrap?嗯,你看,每个monad都不一样.每个人都需要自己的解包装.许多这些有字"跑"在其中,例如runST,runContrunEval.但是,对于某些monad来说,打开它们可能并不安全(因此需要不同的unwrappers).

列表的一个实现是head.但是如果列表是空的怎么办?一个unwrapper for Maybeis fromJust,但如果它是Nothing什么?

同样,Eithermonad的unwrapper将是这样的:

fromRight :: Either a b -> b
fromRight (Right x) = x
Run Code Online (Sandbox Code Playgroud)

但是这个解包器并不安全:如果你有一个Left价值怎么办?(左侧通常表示错误状态,在您的情况下,是一个解析错误).所以最好的办法时的行动Either值是使用either功能,或者使用一个case语句匹配RightLeft,丹尼尔·瓦格纳所示.

tl;博士:没有magicMonadUnwrap.如果你在同一个monad中,你可以使用<-,但要真正从monad中提取价值......好吧......你怎么做取决于你正在处理的monad.


Dan*_*ner 7

使用case.

main = do
    ...
    case csv_data of
        Left  err -> {- whatever you're going to do with an error -- print it, throw it as an exception, etc. -}
        Right csv -> printCSV csv
Run Code Online (Sandbox Code Playgroud)

either功能是短(语法明智),但归结为同样的事情.

main = do
    ...
    either ({- error condition function -}) printCSV csv_data
Run Code Online (Sandbox Code Playgroud)