Сталкивающиеся монады (Text.JSON.Result

#haskell

#хаскелл

Вопрос:

Приведенный ниже код включает в себя использование 2 монад, и каким-то образом мне нужно накручивать и переносить фактические данные через типы read_field .

Что я хотел бы сделать, так это иметь возможность извлекать строку из результирующей монады (если все в порядке), а затем передавать ее в get_field , затем, когда она выйдет, оберните ее в результат и отправьте в main либо для печати, либо для исправления ошибок.

 module Main where
import System.IO
import System.Environment
import Text.Printf
import Text.JSON.Generic
import Text.JSON.Types
import Text.JSON

touchJSONfile path = do
  -- Touches a file into existence. The good touch.
  writeFile path "{}n"
  return ()


read_field :: String -> String -> IO String
read_field filename key = do
  result <- readFile filename
  let json_data = decode result :: Result JSValue
  value <- json_data >>= x -> get_field x key     -- right here
  return (value)



main :: IO ()
main = do
  args <- getArgs
  case head args of
    "init-store" ->  touchJSONfile (args !! 1)
    "set-keyf" -> putStrLn $ show args  --stub
    "set-keyi" -> putStrLn $ show args  --stub
    "get-key" -> putStrLn $ read_field ( args !! 1 )  (args !! 2)
    _ -> putStrLn "Error, command not accepted"

  return ()
  

Комментарии:

1. return () In main не нужен; кроме того, вы можете закончить read_field просто json_data >>= ... ; нет необходимости использовать return . В Haskell также принято использовать camelCase, а не подчеркивания.

Ответ №1:

Хорошо, я делаю несколько предположений. Текст в вашем файле json должен быть:

 { "somekeyyousearchfor : "somevalueyouwant" }
  

В этом случае давайте сделаем это шаг за шагом. Сначала у нас есть результат:

 read_field filename key = do
  result <- readFile filename
  let res = decode result :: Result JSValue
  

Результат либо Ok JsValue, либо строка ошибки, поэтому:

 read_field filename key = do
  result <- readFile filename
  let json_data = decode result :: Result JSValue
  return $ case res of
    Error e -> ""
    Ok json_data -> undefined
  

Пока все хорошо. Теперь у нас есть json_data, который является значением JsValue. Входные данные, которые у нас есть, — это объект, поэтому:

 read_field filename key = do
    result <- readFile filename
    let json_data = decode result :: Result JSValue
    return $ case res of
      Error e -> ""
      Ok json_data -> case json_data of
        JSObject ob -> undefined
        _ -> ""
  

Хорошо, теперь у нас есть JSObject, где ob — JsValue JSObject . Этот JSObject является новым типом, а не конструктором, как предыдущий, но может использовать для него функцию get_field, поэтому:

 read_field filename key = do
  result <- readFile filename
  let json_data = decode result :: Result JSValue
  return $ case res of
    Error e -> ""
    Ok json_data -> case json_data of
      JSObject ob -> case (get_field ob key) of
        Just (JSString str) -> ""
        _ -> ""
      _ -> ""
  

Он вернул только JsValue , и поскольку мы предполагаем, что это будет строка, нас не волнуют никакие другие значения. Итак, это JSString, который является оболочкой вокруг обычной строки, поэтому:

 read_field :: String -> String -> IO String
read_field filename key = do
  result <- readFile filename
  let res = decode result :: Result JSValue
  return $ case res of
    Error e -> ""
    Ok json_data ->
      case json_data of
        JSObject ob -> case (get_field ob key) of
          Just (JSString str) -> fromJSString str
          _ -> ""
        _ -> ""
  

Немного раздражает, но есть другая библиотека под названием aeson, которая делает все совсем по-другому, и она немного более компактна, но и немного сложнее. В списке haskell-beginners, который я недавно опубликовал, есть хороший пример того, как его использовать.

Ответ №2:

Попробуйте что-то вроде этого:

 read_field :: String -> String -> IO String
read_field filename key = do
  result <- readFile filename
  case decode result of
    OK value  -> get_field value key
    Error err -> error err -- Do something with the error case; for now, kill the program.