Развертывание монады - PullRequest
       14

Развертывание монады

5 голосов
/ 23 августа 2011

Учитывая приведенную ниже программу, у меня возникают проблемы, связанные с монадами.

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. 

csv_data - это CSV-тип Either (parseerror), а 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"
!       

ссылка: http://hackage.haskell.org/packages/archive/csv/0.1.2/doc/html/Text-CSV.html

Ответы [ 2 ]

10 голосов
/ 23 августа 2011

Относительно монад:

Да, Either a - это монада.Итак, чтобы упростить задачу, вы в основном просите об этом:

main = print $ magicMonadUnwrap v

v :: Either String Int
v = Right 3

magicMonadUnwrap :: (Monad m) => m a -> a
magicMonadUnwrap = undefined

Как вы определяете magicMonadUnwrap?Ну, вы видите, это отличается для каждой монады.Каждому нужен свой собственный распаковщик.У многих из них есть слово «бежать», например, runST, runCont или runEval.Однако для некоторых монад, возможно, небезопасно их разворачивать (отсюда и необходимость в развертываниях по-разному).

Одна реализация для списков будет head.Но что, если список пуст?Развертывание для Maybe - это fromJust, но что, если это Nothing?

Точно так же развертывание для монады Either будет выглядеть примерно так:

fromRight :: Either a b -> b
fromRight (Right x) = x

Ноэтот распаковщик небезопасен: что, если вместо этого у вас было значение Left?(Слева обычно представляет состояние ошибки, в вашем случае, ошибка разбора).Таким образом, лучший способ воздействовать на значение Either - это использовать функцию either или использовать оператор case, соответствующий Right и Left, как иллюстрировал Даниэль Вагнер.

tl; dr : нет magicMonadUnwrap.Если вы находитесь внутри той же монады, вы можете использовать <-, но чтобы действительно извлечь значение из монады ... ну ... как вы это сделаете, зависит от того, с какой монадой вы имеете дело.

7 голосов
/ 23 августа 2011

Использование 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

Функция either короче (по синтаксису), но сводится к тому же.

main = do
    ...
    either ({- error condition function -}) printCSV csv_data
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...