2013-04-10 3 views
4

Я новичок программист haskell, и я пытаюсь написать Haskell cgi, который будет читать из базы данных MySQL и выводить JSON. Я могу генерировать правильный JSON, но я не могу правильно получить типы данных, чтобы правильно выводить JSON. Я также думаю, что я в первую очередь думаю, что все еще необходимо. Вот мой код. Обратите внимание: getTopBrands предоставляет json-выход.Haskell design: Борьба с IO

Моя проблема в том, что я не могу понять, как вернуть «[Char]» из getTopBrands, а не «IO [Char]». Мне кажется, я все еще думаю, что это необходимо. Любые указатели, предложения по исправлению этого будут весьма признательны. Пожалуйста, дайте мне знать, если мне нужно предоставить остальную часть кода.

RODB.hs:

{-# LANGUAGE RecordWildCards, OverloadedStrings, PackageImports #-} 

module Main where 

import RODB 
import ROOutput 
import System.Environment 
import Database.HDBC 
import Network.Socket(withSocketsDo) 
import Network.CGI 
import Text.XHtml 
import qualified "bytestring" Data.ByteString.Lazy.Char8 as LBS 
import Data.Aeson 

page :: Html 
page = body << h1 << str 

main = runCGI $ handleErrors cgiMain 

cgiMain :: CGI CGIResult 
cgiMain = 
    do out <- getTopBrands 10 1 
     setHeader "Content-type" "application/json" 
     output $ renderHtml page out 

getTopBrands :: Integer -> Integer -> IO [Char] 
getTopBrands limit sorted = 
    do let temp = 0 
     dbh <- connect "127.0.0.1" "ReachOutPublicData" "root" "admin" "/tmp/mysql.sock" 
     if sorted == 1 
     then do brandlist <- getBrands dbh limit True 
       json <- convPublicBrandEntrytoJSON brandlist 
       return $ LBS.unpack json 
     else do brandlist <- getBrands dbh limit False 
       json <- convPublicBrandEntrytoJSON brandlist 
       return $ LBS.unpack json 
+6

В чем проблема с 'IO' здесь? В конце концов, результат функции * зависит от результата операции ввода-вывода, поэтому я не буду рассматривать этот плохой стиль. Более очевидной проблемой здесь является параметр 'sorted', который имеет тип' Integer'. Если у него был тип 'Bool', вы могли бы передать его непосредственно на' getBrands' без уродливой ветви и дублирования кода. Я также не понимаю, почему 'convPublicBrandEntrytoJSON' должен будет жить в' IO', но поскольку вы не указали его определение, я не могу предложить улучшения здесь. –

ответ

8

Как Niklas B said, getTopBrands будучи в IO прав, так как это зависит от ввода/вывода. Я думаю, ваша проблема в том, что вы получите ошибку типа от этого, когда вы пытаетесь использовать его непосредственно,

cgiMain :: CGI CGIResult 
cgiMain = 
    do out <- getTopBrands 10 1 
     setHeader "Content-type" "application/json" 
     output $ renderHtml page out 

, поскольку все заявления в сделай блок должен принадлежать к одной и той же монады, а остальная часть блока в CGI. Но, CGI является MonadIO, таким образом, вы можете просто liftIO его в CGI,

cgiMain :: CGI CGIResult 
cgiMain = 
    do out <- liftIO $ getTopBrands 10 1 
     setHeader "Content-type" "application/json" 
     output $ renderHtml page out 

Следующая точка Никлас поднятый также право, второй Integer аргумент getTopBrands должен быть действительно Bool. Тем не менее, даже с его текущим типом, дублирование кода совершенно не нужно, разница между этими двумя ветвями только Bool аргумента getBrands, так

getTopBrands :: Integer -> Integer -> IO [Char] 
getTopBrands limit sorted = 
    do let temp = 0 
     dbh <- connect "127.0.0.1" "ReachOutPublicData" "root" "admin" "/tmp/mysql.sock" 
     brandlist <- getBrands dbh limit (sorted == 1) 
     json <- convPublicBrandEntrytoJSON brandlist 
     return $ LBS.unpack json 

просто передать это условие, на котором вы разветвленный.

третья точка Никлас

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

также выглядит очень достоверно, преобразование обычно будет чистой функцией. Если единственная причина, почему в IO является возможность писать

json <- convPublicBrandEntrytoJSON brandlist 

вы должны знать, что вы можете связать результаты чистых функций в сделай блок

let json = convPublicBrandEntrytoJSON brandlist 

с использованием let.

+0

Спасибо, Дэниэл, liftIO выполнил эту работу для меня. – Animesh