Написание экземпляра liftIO для типа результата Text.JSON - PullRequest
2 голосов
/ 14 ноября 2010

Библиотека Haskell Text.JSON использует абстрактный тип данных с именем Result, в основном это их форма Maybe, но вместо Nothing есть строка ошибки. Как бы то ни было, мне нужно использовать liftIO для преобразования вызова функции, возвращающей IO, в Result внутри моей реализации JSON.readJSON. Я новичок в монадных преобразователях и, похоже, не могу реализовать liftIO для Result (я продолжаю пытаться создать бесконечный тип, согласно ghci).

Есть идеи?

Большое спасибо

EDIT

Извините, что у меня ушло так много времени на разработку! Я ценю вашу помощь, ребята.

  readJSON (JSObject obj) = do text <- getVal obj "text"
                           user <- getVal obj "from_user"
                           iden <- getVal obj "id_str"
                           url <- (do if (length.extractURLs) text == 0
                                           then return ""
                                           else return $ head $ extractURLs text)
                           title <- liftIO (getSiteTitle url)
                           return $ 
                            Tweet 
                              NewsStory {
                                          title = "Twitter",
                                          desc = text,
                                          url = url,
                                          metric = 0,
                                          sourceURL = "twitter.com/" ++ user  ++ "/status/" ++ iden
                                        }

Таким образом, последняя строка перед возвратом использует getSiteTitle для анализа веб-сайта по этому URL на предмет его заголовка. Тем не менее, эта функция возвращает тип IO String, и компилятор говорит мне, что хочет, чтобы она была Result. Это невозможно?

Еще раз спасибо!

EDIT2

Я решил исключить заголовок из моего типа данных и получить его позже, когда он находится внутри монады ввода-вывода. Спасибо всем за помощь! Я, безусловно, научился этому вопросу.

Ответы [ 3 ]

5 голосов
/ 14 ноября 2010

Вы не можете использовать IO внутри readJSON (не прибегая к unsafePerformIO). liftIO используется, когда у вас есть стек монадных трансформаторов с IO внизу. Возможно, если вы дадите более конкретную информацию о том, чего пытаетесь достичь, вы сможете получить более полезный ответ:)

2 голосов
/ 14 ноября 2010

То, что вы хотите, невозможно.В пакете json readJSON :: JSValue -> Result a.По определению это чистая функция.Возможно, вы могли бы создать результат для чего-то с IO внутри, но тогда было бы невозможно выполнить showJSON :: a -> JSValue.

Мое решение?Я бы дал вашему типу данных title :: Maybe String и затем сделал бы второй проход ввода-вывода, который бы заполнил заголовки.

1 голос
/ 14 ноября 2010

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

Поскольку вы хотите использовать IO для получения URL-адреса, вам придется разделить вашу функцию на две функции: одну в монаде JSON и одну в монаде IO. Поскольку вы не можете «запустить» монаду ввода-вывода, вам придется запустить монаду JSON внутри ввода-вывода, здесь doAll - еще одна функция для объединения двух.

Вам нужно будет немного отредактировать его, чтобы он соответствовал используемой вами библиотеке JSON - некоторые из сигнатур типов не заполнены, и я не знаю, что такое функция "run" и какие типы возвращают ваша монада JSON :

-- This one is in the JSON monad...
-- The type sig needs fixing...
readJSON :: JSObject ?? -> GetJSON (String,String,String,String)
readJSON (JSObject obj) = do 
    text <- getVal obj "text"
    user <- getVal obj "from_user"
    iden <- getVal obj "id_str"
    url <- (do if (length.extractURLs) text == 0
               then return ""
               else return $ head $ extractURLs text)
    return (text,user,iden,url)

-- This one is in IO...
ioStep :: (String,String,String,String) -> IO TweetNewsStory
ioStep (text,user,iden,url) = do
  title <- getSiteTitle url
  return $ TweetNewsStory {
             title = "Twitter",
             desc = text,
             url = url,
             metric = 0,
             sourceURL = "twitter.com/" ++ user  ++ "/status/" ++ iden
           }


-- Type sig needs fixing...
-- The JSON library will provide something similar to
-- runJSON...
--
doAll :: JSObject ?? -> IO TweetNewsStort
doAll jsobj = 
    let ans = runJSON $ readJSON jsobj in 
     case ans of 
       Left err -> error $ err
       Right val -> ioStep val
...