рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ xkcd рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╣рд╛рд╕реНрдХреЗрд▓ рдХреЗ рд╕рд╛рде рдПрдХ рд╡реЗрдм рдХреЙрдорд┐рдХ рд╕реЗ рдПрдХ рдкреАрдбреАрдПрдл рдкреБрд╕реНрддрдХ рдмрдирд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рдЬрд╛ рд░рд╣реА рд╣реИ

рд▓реЗрдЦ рдкрдврд╝рдиреЗ рдХреЗ рдмрд╛рдж , рдореИрдВрдиреЗ рдпрд╣ рдЬрд╛рдВрдЪрдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдХрд┐ рд╣рд╛рд╕реНрдХреЗрд▓ рдЗрд╕рдХреЗ рд▓рд┐рдП рдХрд┐рддрдирд╛ рдЙрдкрдпреБрдХреНрдд рд╣реИред рдореИрдВ рддреБрд░рдВрдд рдпрд╣ рдХрд╣рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ рдХрд┐ рд╣рд╛рд╕реНрдХреЗрд▓ рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рдХрд╛рдлреА рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди hackage.haskell.org рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЪрд▓ рд░рд╣рд╛ рд╣реИ, рдореБрдЭреЗ рддреБрд░рдВрдд рдкреАрдбреАрдПрдл рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛рдПрдВ рдорд┐рд▓реАрдВ, рдЬрд┐рд╕рдиреЗ рдкреВрд░реНрдг рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рд░реЛрдХ рд▓рдЧрд╛ рджреАред

рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдлрд┐рд░ рднреА рдХреБрдЫ рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рддрд╛рдХрд┐ рдпрд╣ рджрд┐рдЦрд╛рдпрд╛ рдЬрд╛ рд╕рдХреЗ рдХрд┐ рд╣рд╛рд╕реНрдХреЗрд▓ рдореЗрдВ рдПрдХ рд╣реА рдХрд╛рдо рдХреИрд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ , рдЕрдЧрд░ рдХреЗрд╡рд▓ ...



рдХреЙрдорд┐рдХ рдмреБрдХ рдХреА рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ


рдЪреВрдВрдХрд┐ рд╣рдореЗрдВ JSON рдХреЗ рд░реВрдк рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдХрд╛ рдЕрдиреБрд░реЛрдз рдХрд░рдирд╛ рд╣реИ, рд╣рдо рддреБрд░рдВрдд рдПрдХ рдЙрдкрдпреЛрдЧреА рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦреЗрдВрдЧреЗ:

rethrow :: ( Show e ) => Exceptional ea -> IO a<br>

rethrow = switch ( throwIO . userError . show ) return<br>

<br>

jsonAt url = simpleHTTP ( getRequest url ) >>= getResponseBody >>= rethrow . decode_ json<br>

<br>

str s = member_ ( literal s ) JSON . string<br>

num n = member_ ( literal n ) JSON . number<br>









rethrow



рдлрд╝рдВрдХреНрд╢рди рдПрдХ рдЕрдкрд╡рд╛рдж rethrow



рдлреЗрдВрдХ rethrow



рдЬрдм рдЧрд▓рдд рддрд░реАрдХреЗ рд╕реЗ рдкрд╛рд░реНрд╕рд┐рдВрдЧ, рдФрд░ str



рдФрд░ num



JSON рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рдлрд╝реАрд▓реНрдб рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рдЖрд╕рд╛рди рдмрдирд╛ рджреЗрдЧрд╛ред



рдлрд┐рд░ рдЕрдВрддрд┐рдо рдХреЙрдорд┐рдХ рдФрд░ рдирдВрдмрд░ рд╕реЗ рдХреЙрдорд┐рдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдб рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛:

comics = jsonAt "http://xkcd.com/info.0.json" >>= fmap ( fromIntegral . numerator ) . rethrow . decode_ ( num "num" ) <br>

<br>

comic n = jsonAt ( concat [ "http://xkcd.com/" , show n , "/info.0.json" ] ) >>= rethrow . decode_ ( str "img" <&> str "title" ) <br>







decode_



рдлрд╝рдВрдХреНрд╢рди рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдкреИрдЯрд░реНрди рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдкреНрд░рд╛рдкреНрдд рдбреЗрдЯрд╛ рдХреЛ decode_



ред num "num"





рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ num "num"





рд╣рдореЗрдВ JSON рд╕реЗ рдПрдХ рд╕рдВрдЦреНрдпрд╛рддреНрдордХ рд╕рджрд╕реНрдп рдХрд╛ рдирд╛рдо рдорд┐рд▓рд╛ рд╣реИ, рдЬреЛ str "img" <&> str "title"





str "img" <&> str "title"





- рдХреНрд░рдорд╢рдГ рдЪрд┐рддреНрд░ рдФрд░ рдирд╛рдо рдХреЗ рд▓рд┐рдП рджреЛ рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХрд╛ рдмреЗрд╡рдХреВрдлред



URL рджреНрд╡рд╛рд░рд╛ рдЪрд┐рддреНрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХрд╛ рдХреЛрдб:

image url = simpleHTTP ( getRequest url ) >>= getResponseBody<br>









рдбрд╛рдЙрдирд▓реЛрдб рд╕реНрдЯреНрд░реАрдо


рд╣рдо рдПрдХ рдЕрд▓рдЧ рдХрд╛рд░реНрдп рдореЗрдВ рдПрдХ рдХреЙрдорд┐рдХ рдХрд╛ рдбрд╛рдЙрдирд▓реЛрдб рд▓рд┐рдЦрддреЗ рд╣реИрдВред

retrieve ch li = tryGet `onException` onFail where <br>

onFail = do <br>

writeChan ch ( i , Nothing ) <br>

writeLogger l Error $ "Comic " ++ show i ++ " failed to download" <br>

tryGet = do <br>

( imgUrl , title ) <- comic i<br>

imgData <- image imgUrl<br>

jpg <- writeBinaryFile fname imgData >> readJpegFile fname >>= either ( throwIO . userError . show ) return<br>

writeChan ch ( i , Just ( jpg , title ) ) <br>

writeLogger l Info $ "Comic " ++ show i ++ " downloaded" <br>

fname = show i ++ ".jpg" <br>









рдпрд╣рд╛рдВ рд╣рдордиреЗ ch



рдЪреИрдирд▓ ( Control.Concurrent.Chan



) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛, рдЬрд┐рд╕рд╕реЗ рд╣рдо рдбрд╛рдЙрдирд▓реЛрдб рдкрд░рд┐рдгрд╛рдо рднреЗрдЬреЗрдВрдЧреЗ, рд╕рд╛рде рд╣реА рдереНрд░реЗрдб-рд╕реЗрдл рд▓реЙрдЧ l



ред



рдПрдЪрдкреАрдбреАрдПрдл рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреА рд╡рдХреНрд░ рдХреЗ рдХрд╛рд░рдг, рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рдЫрд╡рд┐ рдХреЛ рдПрдХ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╕рд╣реЗрдЬрдирд╛ рд╣реЛрдЧрд╛, рдФрд░ рдлрд┐рд░ рдЗрд╕реЗ рдлрд┐рд░ рд╕реЗ рд╡рд╣рд╛рдВ рд╕реЗ рд▓реЛрдб рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИ рдХрд┐ рд▓реЗрдЦрдХ рдиреЗ рдЬреЗрдкреАрдИрдЬреА рдХреЛ рд╕реНрд╡рдпрдВ рдЦрд░реЛрдВрдЪ рд╕реЗ (рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдХреЗрд╡рд▓ рдПрдХ рдлрд╝рд╛рдЗрд▓ рд╕реЗ) рдкрд╛рд░реНрд╕ рдХреНрдпреЛрдВ рд▓рд┐рдЦрд╛, рд▓реЗрдХрд┐рди рддреИрдпрд╛рд░ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛



рдкреАрдбреАрдПрдл рдЬрдирд░реЗрд╢рди


рдЕрдм рдпрд╣ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд╛рдпрдХ рд╣реИ рдЬреЛ рдЪрд┐рддреНрд░реЛрдВ рдХреА рд╕реВрдЪреА рд╕реЗ рдкрд░рд┐рдгрд╛рдореА рдкреАрдбреАрдПрдл рдЙрддреНрдкрдиреНрди рдХрд░реЗрдЧрд╛ред

pdf imgs = runPdf "Xkcd.pdf" doc ( PDFRect 0 0 800 600 ) $ forM_ imgs genPage where <br>

genPage ( jpeg , title ) = do <br>

img <- createPDFJpeg jpeg<br>

page <- addPage Nothing <br>

drawWithPage page ( drawText ( text ( PDFFont Times_Roman 12 ) 0 0 ( toPDFString title ) ) >> drawXObject img ) <br>

doc = PDFDocumentInfo { <br>

author = toPDFString "xkcd" , <br>

subject = toPDFString "xkcd" , <br>

pageMode = UseNone , <br>

pageLayout = OneColumn , <br>

viewerPreferences = standardViewerPrefs , <br>

compressed = False } <br>







рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдХреБрдЫ рднреА рджрд┐рд▓рдЪрд╕реНрдк рдирд╣реАрдВ рд╣реИред рд╣рдо рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдХрд╣рддреЗ рд╣реИрдВред рдХреЗрд╡рд▓ рдЕрддрд┐ рд╕реВрдХреНрд╖реНрдо рдЕрдВрддрд░ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рдХрд┐ рдЪрд┐рддреНрд░реЛрдВ рдХреА рд╕реВрдЪреА рдЖрд▓рд╕реА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдкрд╣рд▓реА рддрд╕реНрд╡реАрд░ рджрд┐рдЦрд╛рдИ рджреЗрддреЗ рд╣реА рдлрд╝рдВрдХреНрд╢рди рдХрд╛рдо рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рджреЗрддрд╛ рд╣реИред



рдЗрд╕реЗ рдПрдХ рд╕рд╛рде рд░рдЦрдирд╛


рдореБрдЦреНрдп рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ, рд╣рдо рд▓реЙрдЧ рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рддреЗ рд╣реИрдВ, рдПрдХ рдЪреИрдирд▓ рдмрдирд╛рддреЗ рд╣реИрдВ рдЬрд┐рд╕рдореЗрдВ рд╣рд▓реНрдХреЗ рдзрд╛рдЧреЗ рдкрд░рд┐рдгрд╛рдо рд▓рд┐рдЦреЗрдВрдЧреЗ, рдФрд░ рдЗрд╕ рдЪреИрдирд▓ рд╕реЗ рддрд╕реНрд╡реАрд░реЛрдВ рдХреА рдПрдХ рдЖрд▓рд╕реА рд╕реВрдЪреА рдХреЗ рд╕рд╛рде рдкреАрдбреАрдПрдл рдХреА рдкреАрдврд╝реА рдХрд╛ рдХрд╛рд░рдг рдмрдиреЗрдВрдЧреЗред

main = bracket ( newLogger Console ) closeLogger $ \ l -> do <br>

n <- comics<br>

writeLogger l Info $ "Number of comics to download: " ++ show n<br>

ch <- newChan<br>

mapM_ ( fork . retrieve ch l ) [ 1 .. n ] <br>

cts <- fmap ( take n ) $ getChanContents ch<br>

let imgs = catMaybes $ mapMaybe ( `lookup` cts ) [ 1 .. n ] <br>

pdf imgs `onException` ( writeLogger l Error "Unable to generate PDF" ) <br>

writeLogger l Info "PDF generated." <br>







bracket



рдлрд╝рдВрдХреНрд╢рди рдХрд╛ using



рдХрд░рдирд╛ рд╕рдорд╛рди рд╣реИ, рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдирд╛ рдХрд┐ рд▓реЙрдЧ рдмрдВрдж рд╣реИред

mapM_ ( fork . retrieve ch l ) [ 1 .. n ] <br>





mapM_ ( fork . retrieve ch l ) [ 1 .. n ] <br>





рд╣рдо рдкреНрд░рддреНрдпреЗрдХ рдирдВрдмрд░ рдХреЗ рд▓рд┐рдП рдПрдХ рдбрд╛рдЙрдирд▓реЛрдб рд╕реНрдЯреНрд░реАрдо рдмрдирд╛рддреЗ рд╣реИрдВ, рдЕрд░реНрдерд╛рдд рдХреЙрд▓ retrieve ch li



рдХрд░реЗрдВ retrieve ch li



рдПрдХ рдЕрд▓рдЧ рдереНрд░реЗрдб рдореЗрдВред

fmap ( take n ) $ getChanContents ch<br>





рдкрд╣рд▓реЗ n



рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЗ рд╕рд╛рде рд╣рдореЗрдВ рдПрдХ рдЖрд▓рд╕реА рд╕реВрдЪреА рд▓реМрдЯрд╛рдПрдЧрд╛ред рд▓реАрдЬрд┐рдП рдкреВрд░реА рд╕реВрдЪреА рдХрд╛ рдХреЛрдИ рдорддрд▓рдм рдирд╣реАрдВ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЪреИрдирд▓ рдЕрдВрддрд╣реАрди рд╣реИред

рдлрд┐рд░ рд╣рдо рдХреНрд░рдо рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рд╕реВрдЪрдХрд╛рдВрдХ рдХреЗ рд╕рд╛рде, 1



рд╕реЗ n



рддрдХ lookup



рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рдПрдХ рдЖрд▓рд╕реА рд╕реВрдЪреА рдХреЗ рд░реВрдк рдореЗрдВ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рд▓реЗрдХрд┐рди рдЬрд┐рд╕рдореЗрдВ рдЪрд┐рддреНрд░ рдХреНрд░рдо рдореЗрдВ рд╕рдЦреНрддреА рд╕реЗ рдЪрд▓рддреЗ рд╣реИрдВред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдо рд╣рдореЗрд╢рд╛ рд╕рд╣реА рдХреНрд░рдо рдореЗрдВ рдЪрд┐рддреНрд░ рд▓рд┐рдЦреЗрдВрдЧреЗред



рдкреВрд░реА рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ


main = bracket ( newLogger Console ) closeLogger $ \ l -> do <br>

n <- comics<br>

writeLogger l Info $ "Number of comics to download: " ++ show n<br>

ch <- newChan<br>

mapM_ ( fork . retrieve ch l ) [ 1 .. n ] <br>

cts <- fmap ( take n ) $ getChanContents ch<br>

let imgs = catMaybes $ mapMaybe ( `lookup` cts ) [ 1 .. n ] <br>

pdf imgs `onException` ( writeLogger l Error "Unable to generate PDF" ) <br>

writeLogger l Info "PDF generated." <br>

<br>

retrieve ch li = tryGet `onException` onFail where <br>

onFail = do <br>

writeChan ch ( i , Nothing ) <br>

writeLogger l Error $ "Comic " ++ show i ++ " failed to download" <br>

tryGet = do <br>

( imgUrl , title ) <- comic i<br>

imgData <- image imgUrl<br>

jpg <- writeBinaryFile fname imgData >> readJpegFile fname >>= either ( throwIO . userError . show ) return<br>

writeChan ch ( i , Just ( jpg , title ) ) <br>

writeLogger l Info $ "Comic " ++ show i ++ " downloaded" <br>

fname = show i ++ ".jpg" <br>

<br>

pdf imgs = runPdf "Xkcd.pdf" doc ( PDFRect 0 0 800 600 ) $ forM_ imgs genPage where <br>

genPage ( jpeg , title ) = do <br>

img <- createPDFJpeg jpeg<br>

page <- addPage Nothing <br>

drawWithPage page ( drawText ( text ( PDFFont Times_Roman 12 ) 0 0 ( toPDFString title ) ) >> drawXObject img ) <br>

doc = PDFDocumentInfo { <br>

author = toPDFString "voidex" , <br>

subject = toPDFString "xkcd" , <br>

pageMode = UseNone , <br>

pageLayout = OneColumn , <br>

viewerPreferences = standardViewerPrefs , <br>

compressed = False } <br>

<br>

rethrow :: ( Show e ) => Exceptional ea -> IO a<br>

rethrow = switch ( throwIO . userError . show ) return<br>

<br>

jsonAt url = simpleHTTP ( getRequest url ) >>= getResponseBody >>= rethrow . decode_ json<br>

<br>

str s = member_ ( literal s ) JSON . string<br>

num n = member_ ( literal n ) JSON . number<br>

<br>

comics = jsonAt "http://xkcd.com/info.0.json" >>= fmap ( fromIntegral . numerator ) . rethrow . decode_ ( num "num" ) <br>

<br>

comic n = jsonAt ( concat [ "http://xkcd.com/" , show n , "/info.0.json" ] ) >>= rethrow . decode_ ( str "img" <&> str "title" ) <br>

<br>

image url = simpleHTTP ( getRequest url ) >>= getResponseBody<br>

<br>

writeBinaryFile fname str = withBinaryFile fname WriteMode ( \ h -> hPutStr h str ) <br>









рджреБрд░реНрд╡рдЪрди


рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдкреАрдбреАрдПрдл рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рднреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреА рдХрдореА рдХреЗ рдХрд╛рд░рдг, рдкрд░рд┐рдгрд╛рдо рдХрд╛ рднреБрдЧрддрд╛рди рдирд╣реАрдВ рд╣реБрдЖред

рдЕрдзрд┐рдХрд╛рдВрд╢ рдЫрд╡рд┐рдпрд╛рдВ рдПрдЪрдкреАрдбреАрдПрдл рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рдиреЗ рд╕реЗ рдЗрдирдХрд╛рд░ рдХрд░рддреА рд╣реИрдВ (рдЬреЗрдкреАрдИрдЬреА рдЕрдкрд▓реЛрдб рдХреЗ рдПрдХ рдФрд░ рд╕рд╛рдЗрдХрд┐рд▓ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж), рдореБрдЭреЗ рдЫрд╡рд┐рдпреЛрдВ рдХреА рд╕реНрдХреЗрд▓рд┐рдВрдЧ рднреА рд╕рдордЭ рдореЗрдВ рдирд╣реАрдВ рдЖрдИред



рдкреНрд░рд╢рдВрд╕рд╛


рдЬреАрдПрдЪрд╕реАрдЖрдИ рдореЗрдВ рд╕реАрдзреЗ рдЕрдиреБрд░реЛрдз рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдирд╛ рдмрд╣реБрдд рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдерд╛, рдлрд┐рд░ рдЙрдирдореЗрдВ рд╕реЗ рдПрдХ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░реЗрдВ, рдЪрд┐рддреНрд░ рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░реЗрдВ рдФрд░ рд╕рд╣реЗрдЬреЗрдВред рд╕рд╛рд░рд╛ рд╡рд┐рдХрд╛рд╕ рд╡рд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛, рдФрд░ рдлрд┐рд░ рдХреЛрдб рдХреЛ рдПрдХ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ред рдорд▓реНрдЯреАрдлрд╝реНрд░реЗрдбрд┐рдВрдЧ рдХреЛ рдЗрдВрдЯрд░рдлреЗрд╕ рдпрд╛ рдХрд┐рд╕реА рдЕрддрд┐рд░рд┐рдХреНрдд рдХреЛрдб рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рдмрд┐рдирд╛ рдЦрд░рд╛рдм рдХрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдкрд░рд┐рдгрд╛рдо рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп, рд╣рдо рдмрд╕ рдЗрд╕реЗ рдЪреИрдирд▓ рдкрд░ рд▓рд┐рдЦрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХреЗ рджреВрд╕рд░реЗ рдЫреЛрд░ рдкрд░ рдПрдХ рд╣реИрдВрдбрд▓рд░ рд╣реИред рдФрд░ рд╣рдо рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ fork



рдЬреЛрдбрд╝рддреЗ рд╣реИрдВред рд╕рд╛рдорд╛рдиреНрдп рдорд╛рдорд▓реЗ рдореЗрдВ, рд╕рдм рдХреБрдЫ рдЗрддрдирд╛ рд╕рд░рд▓ рдирд╣реАрдВ рд╣реИ, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рд▓реЗрдХрд┐рди рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдЕрдиреБрднрд╡ рд╕реЗ рдореИрдВ рдХрд╣реВрдВрдЧрд╛ рдХрд┐ рдореБрдЭреЗ рдЗрд╕рдХреЗ рд▓рд┐рдП рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдХреЛ рдмрджрд▓рдирд╛ рдХрднреА рдирд╣реАрдВ рдкрдбрд╝рд╛ред



рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, hackage.haskell.org рдХреЛ рджреЗрдЦреЗрдВ , рдЖрд╡рд╢реНрдпрдХ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рджреЗрдЦреЗрдВ, рдФрд░ рдпрджрд┐ рдЖрдк рдкрд╛рддреЗ рд╣реИрдВ, рддреЛ рд╣рд╛рд╕реНрдХреЗрд▓ рдореЗрдВ рд╕рдм рдХреБрдЫ рд▓рд┐рдЦрдиреЗ рдХрд╛ рдореМрдХрд╛ рди рдЪреВрдХреЗрдВ!



All Articles