Написание экземпляра liftIO для типа результата Text.JSON

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

Любые идеи?

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

ИЗМЕНИТЬ

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

  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-адресу на предмет его заголовка. Однако эта функция возвращает тип строки ввода-вывода, и компилятор сообщает мне, что хочет, чтобы она была результатом. Это невозможно?

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

РЕДАКТИРОВАТЬ2

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


person Hojdra    schedule 14.11.2010    source источник
comment
Если я вас правильно понял, то, что вы хотите сделать, невозможно, потому что readJSON должен возвращать значение типа Result whatever, которое не связано с IO. (В любом случае, зачем вам выполнять ввод-вывод для синтаксического анализа JSON?) Но можете ли вы прояснить свой вопрос, например, показав нам код, вызывающий ошибку, и точный текст сообщения об ошибке?   -  person Reid Barton    schedule 14.11.2010
comment
Для тех, кто не в курсе, вот рассматриваемый пакет JSON: hackage.haskell.org/package/json   -  person sclv    schedule 14.11.2010


Ответы (3)


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

person David Powell    schedule 14.11.2010
comment
Спасибо за вашу помощь, я подробно остановился на этом выше. - person Hojdra; 14.11.2010

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

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

person sclv    schedule 14.11.2010

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

Поскольку вы хотите использовать ввод-вывод для получения URL-адреса, вам придется разделить вашу функцию на две функции: одну в монаде JSON и одну в монаде ввода-вывода. Поскольку вы не можете «запустить» монаду ввода-вывода, вам придется запускать монаду 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
person stephen tetley    schedule 14.11.2010
comment
Обратите внимание, что приведенное выше немного неуклюже, есть способы сделать его менее громоздким, изменив поток данных вашей программы. По мере практики вы лучше поймете, как это сделать с немного большим стилем, однако выше показано, как запустить монаду JSON внутри ввода-вывода, которая решает вашу непосредственную проблему. - person stephen tetley; 14.11.2010
comment
Это библиотека Text.JSON, то есть эта: hackage.haskell.org/packages/archive/json/0.3.3/doc/html/ - person Hojdra; 14.11.2010
comment
Я просмотрел эту json-библиотеку, но не смог найти функцию getVal. Вы сами определили эту функцию? - person stephen tetley; 14.11.2010
comment
Я не думаю, что мой приведенный выше код сильно помогает. Посмотрев на библиотеку, я подозреваю, что вам не следует использовать монаду для извлечения данных из JSValue. Возможно, вы захотите использовать монаду Maybe для извлечения полей из списка ассоциаций. Затем вам нужно будет повысить свое значение Maybe до Result с помощью такой функции (// для разрывов строк): switchMaybe :: String - ›Maybe a -› Result a // switchMaybe err_msg Nothing = Error err_msg // switchMaybe _ (Just а) = Хорошо а - person stephen tetley; 14.11.2010