deniok: (Default)
[personal profile] deniok
Писал тут код для генерации однотипных задачек; результат должен был отправляться в TeX'овский файл. По ходу дела прибежали дополнительные требования. Сначала попросили, чтобы ответы жили в отдельном файле, потом чисто текстовую версию, и, наконец, коэффициенты в csv. В итоге, поскольку все усилия были направлены на содержательную генерацию, в IO части получился ужасный копипастный монстр:

-- исходная версия
doLinearProg fileTXT fileTeX fileAns fileDat = do 
   -- создали/открыли файлы
   handleTXT <- openFile fileTXT AppendMode
   handleTeX <- openFile fileTeX AppendMode 
   handleAns <- openFile fileAns AppendMode 
   handleDat <- openFile fileDat AppendMode 
   -- установили кодировку
   hSetEncoding handleTXT utf8_bom
   hSetEncoding handleTeX utf8_bom
   hSetEncoding handleAns utf8_bom
   hSetEncoding handleDat utf8_bom
   -- нагенерили список из 30 случайно-неслучайных структур
   lst <- replicateM 30 gen_pd
   -- забацали на основе каждой структуры текст задачи (taskXXX) 
   -- и склеили все 30 задач в один текст с нумерацией (genText)
   let txt = genText taskTXT lst
   let tex = genText taskTeX lst
   let ans = genText answ lst
   let dat = genText taskDAT lst
   -- записали в файлы
   hPutStr handleTXT txt
   hPutStr handleTeX tex
   hPutStr handleAns ans
   hPutStr handleDat dat
   -- закрыли хэндлы
   hClose handleTXT
   hClose handleTeX
   hClose handleAns
   hClose handleDat


Поглядел я на всё это, и понял, что дело дрянь. Дав волю бунтующему эстетическому чувству, свернул каждую четверку в один вызов через списочно-монадические функции:
doLinearProg fileTXT fileTeX fileAns fileDat = do 
   handles <- zipWithM openFile [fileTXT, fileTeX, fileAns, fileDat]
                                (replicate 4 AppendMode)
   zipWithM hSetEncoding handles
                         (replicate 4 utf8_bom)
   lst <- replicateM 30 gen_pd
   let txts = zipWith genText [taskTXT,taskTeX,answ,taskDAT]
                              (replicate 4 lst)
   zipWithM hPutStr handles txts
   mapM hClose handles
А потом ещё чуть-чуть поморщился и избавился от дурацких replicate 4:
doLinearProg fileTXT fileTeX fileAns fileDat = do 
   handles <- mapM (openFile `flip` AppendMode)
                   [fileTXT, fileTeX, fileAns, fileDat]
   mapM (hSetEncoding `flip` utf8_bom) handles
   lst <- replicateM 30 gen_pd
   let txts = map (genText `flip` lst) 
                  [taskTXT, taskTeX, answ, taskDAT]
   zipWithM hPutStr handles txts
   mapM hClose handles
Использование flip для частичного применения не первого, а второго аргумента функции -- полезная в хозяйстве идиома:
f `flip` y = \x -> f x y

Теперь видна следующая проблема: число 4, как длина списков. Если приедут требования дополнительного выходного формата, придется менять код в трёх местах, неочевидным образом связанных друг с другом. Не лучше ли передавать пары (имя файла, функция-генератор содержимого для него) в нужном количестве, то есть использовать в качестве аргументов функции список таких пар? Сказано -- сделано:
doLinearProg fNmsCGnsPairs = do 
   let fileNames = map fst fNmsCGnsPairs
   let contentGens = map snd fNmsCGnsPairs
   handles <- mapM (openFile `flip` AppendMode) fileNames
   mapM (hSetEncoding `flip` utf8_bom) handles
   lst <- replicateM 30 gen_pd
   let txts = map (genText `flip` lst) contentGens
   zipWithM hPutStr handles txts
   mapM hClose handles
Вы можете сделать мне замечание насчет числа 30. Я с ним полностью согласен, это число вытащено в окончательной версии в качестве параметра doLinearProg. Вызов её в итоге выглядит так
main = doLinearProg 30 
   [("res.txt", taskTXT),
    ("res.tex", taskTeX),
    ("res_answ.txt", answ),
    ("res_dat.csv", taskDAT)]

(offtop)

Date: 2010-02-22 12:28 pm (UTC)
From: [identity profile] asviraspossible.livejournal.com
А вы на GHC 6.12 под Windows пишете? Там нормально всё работает с вводом-выводом по русски? И там библиотеки динамически подгружаются или всё таки статично всё линкуется? И зачем вам BOM нужен? :)

Re: (offtop)

Date: 2010-02-22 01:42 pm (UTC)
From: [identity profile] deni-ok.livejournal.com
(1) Угу, решил вот попробовать 6.12, как раз из-за развитых средств для Unicode-aware Handles:
http://www.haskell.org/pipermail/cvs-libraries/2009-June/010890.html
(2,4) C UTF8 - нормально. Я принял решение прекратить работать под Windows с CP1251 и перейти на UTF8, где это только возможно (а возможно это в подавляющем большинстве нужных мне инструментов). А BOM мне нужен, чтобы всякий тупняк типа notepad.exe открывал всё в правильной кодировке.
(3) И не смотрел

Profile

deniok: (Default)
deniok

February 2022

S M T W T F S
  12345
6789101112
13141516171819
20212223 242526
2728     

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jul. 10th, 2025 12:17 pm
Powered by Dreamwidth Studios