Re[10]: Мастер-класс по ФП
От: Beam Россия  
Дата: 07.01.09 23:09
Оценка:
ОК. Убедили, что так делать не надо

Здравствуйте, deniok, Вы писали:

D>
D>map `flip` [1,2,3]
D>

D>или (для любителей явных операторов) приводим к тому, что просили
D>
D>(***) = flip
D>map *** [1,2,3]
D>


Оригинально.

B>>2. существует функции у которых количество параметров больше двух

D>А тут отложенное неименованное связывание легко рушит семантику

B>>3. можно было бы работать с tuple: fun (_,1) _ ===> \x y -> fun (x,1) y

D>Да-да, вот тут и рушит Представь, что fun это flip и вспомни что вычисления идут лениво слева направо...

Вот здесь не понял. Ведь это ничем не отличается от
let myFun x y = fun (x,1) y in myFun 1 2
И вроде, здесь нет проблем никаких
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Best regards, Буравчик
Re[12]: Мастер-класс по ФП
От: thesz Россия http://thesz.livejournal.com
Дата: 07.01.09 23:12
Оценка:
T>>То есть, он не свопится, когда у нас есть 300 тысяч потоков? (каждый по (327+233)*word_size, то есть, 1.2К)

К>Откуда ты плюс взял?


Просмотрел. Но я нашёл поинтересней.

K>В источнике вроде:

К>

К>327 words when spawned including a heap of 233 words.

К>Да и даже 1.2к * 300000 = 360 М, вроде не так чтоб много

The default suggested stack size is 16 kilowords

Оба-на!
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[8]: Мастер-класс по ФП
От: thesz Россия http://thesz.livejournal.com
Дата: 07.01.09 23:15
Оценка:
T>>>>vA = ...что-то там такое...
S>Ага, так вот они, глобальные переменные в Хаскелле! Все, понял. Действительно, императивные фичи можно реализовать, что радует.

Ну, это уж ты как-то совсем того.

Есть такой сайт, Lambda the Ultimate, назван по серии статей Гая Стила (Guy Steele), одного из разработчиков Java.

В этой серии одна из статей называется "Lambda the Ultimate Imperative". AFAIK, там рассказывается про императивное программирование с точки зрения ЛИ.

Могу ошибаться, правда.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[11]: Мастер-класс по ФП
От: deniok Россия  
Дата: 07.01.09 23:25
Оценка:
Здравствуйте, Beam, Вы писали:



B>>>3. можно было бы работать с tuple: fun (_,1) _ ===> \x y -> fun (x,1) y

D>>Да-да, вот тут и рушит Представь, что fun это flip и вспомни что вычисления идут лениво слева направо...

B>Вот здесь не понял. Ведь это ничем не отличается от

B>let myFun x y = fun (x,1) y in myFun 1 2
B>И вроде, здесь нет проблем никаких

У тебя два неименованных места для будущего связывания
myComb = fun (_,1) _

Если потом вызвать
myComb x y

то связывание просто по месту не пройдет, нужны имена (обычная лямбда) или номера (индексы де Бр(ой)(ау)на). Поскольку если fun у тебя, например, такой
fun (a,b) c = c a

то вычисление пойдет так
myComb x y ~> 
(fun (_,1) _)  x y ~>
(_ _) x y ~>
x y
 -- ой мама биндеры переставились, должно-то быть y x
Re[5]: Мастер-класс по ФП
От: FR  
Дата: 08.01.09 04:18
Оценка:
Здравствуйте, thesz, Вы писали:

T>Сделай-ка аналогичный "ассемблер" на твоём любимом ЯП. Чтобы не менее удобно было — чтобы можно было определять свои "подпрограммы" и тп.


Если любимый язык forth то легко

http://netlib.narod.ru/library/book0001/ch03_11.htm
Re[8]: Мастер-класс по ФП
От: geniepro http://geniepro.livejournal.com/
Дата: 08.01.09 05:26
Оценка: 4 (1)
Здравствуйте, deniok, Вы писали:

D>Здравствуйте, Beam, Вы писали:



B>>Кстати, почему в Haskell не сделают что-то типа

B>>map _ [1,2,3] as \f -> map f [1,2,3]
B>>Ну т.е. аналогично scheme.

D>А зачем, если можно с той же целью написать

D>
D>flip map [1,2,3]
D>

или так:
(`map` [1,2,3])
Re[7]: Мастер-класс по ФП
От: BulatZiganshin  
Дата: 08.01.09 09:13
Оценка:
Здравствуйте, Beam, Вы писали:

B>Кстати, почему в Haskell не сделают что-то типа

B>map _ [1,2,3] as \f -> map f [1,2,3]

я слышал, что проблема в том, что непонятно, где вставлять \_. например в твоём примере:
map (\f -> f) [1,2,3]
или
\f -> map f [1,2,3]
или
(\f -> map f) [1,2,3]
Люди, я люблю вас! Будьте бдительны!!!
Re: Мастер-класс по ФП
От: Tonal- Россия www.promsoft.ru
Дата: 08.01.09 10:53
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:
Просили продолжения
Автор: Mr.Cat
Дата: 07.01.09
, как обществу такая задачка:
Дано:
Дерево в текстовом файле. Новый уровень +2 пробела, типа такого:
Животные
  рыбы
    щука
    карась
  птицы
    перепел
Растения
  ...

Нужно:
1. Зачитать это в
data Tree = Leaf Int String | Tree Int String [Tree]

где Int — номер строки, String — строка без начатльных и конечных пробелов
2. Сделать чтение устойчивым к ошибкам пропуска уровня типа:
Животные
    карась
  птицы
    перепел
Растения
  ...

3. Написать код печати дерева в исходном виде
4. Отфильтровать дерево, оставив только ветви содержащие дубликаты и сами дубликаты.
... << RSDN@Home 1.2.0 alpha 4 rev. 0>>
Re[13]: Мастер-класс по ФП
От: Курилка Россия http://kirya.narod.ru/
Дата: 08.01.09 12:12
Оценка:
Здравствуйте, thesz, Вы писали:

T>>>То есть, он не свопится, когда у нас есть 300 тысяч потоков? (каждый по (327+233)*word_size, то есть, 1.2К)


К>>Откуда ты плюс взял?


T>Просмотрел. Но я нашёл поинтересней.


[cut]

T>The default suggested stack size is 16 kilowords


T>Оба-на!


Ммм, Сергей, думаю стоит внимательней читать, ну какое отношение стэк эмулятора имеет к памяти тех процессов, которые в нём крутятся?
И чуть ниже смотрим:

+h Size
Sets the default heap size of processes to the size Size.

Вот этот другой (а не +a size) параметр задаёт размер хипов процессов.
Re[2]: Мастер-класс по ФП
От: BulatZiganshin  
Дата: 08.01.09 13:38
Оценка: 4 (1)
Здравствуйте, Tonal-, Вы писали:

T>1. Зачитать это в

T>
T>data Tree = Leaf Int String | Tree Int String [Tree]
T>

T>где Int — номер строки, String — строка без начатльных и конечных пробелов

во-первых, проще
data Tree = Tree Int String [Tree]


во-вторых, в постановке задачи ошибка попробуй сам описать, какое дерево должно быть построено по твоим входным данным

task1 =  zip [1..]  -- нумеруем строки
     >>> makeTrees  -- формируем список деревьев

makeTrees =  groupFrom (not.isSpace.head.snd)  -- разбиваем на группы, начинающиеся со строки без отступа
                 -- в каждой из групп первую строчку используем для заголовка дерева
         >>> map ( \((linenum,string):xs) -> Tree linenum string  
                                                  -- а в оставшихся строках отрезаем первые два пробела и 
                                                  -- рекурсивно изготовляем из них список деревьев
                                                  (makeTrees (map (drop 2) xs)))



T>2. Сделать чтение устойчивым к ошибкам пропуска уровня типа:

T>
T>Животные
T>    карась
T>  птицы
T>    перепел
T>Растения
T>  ...
T>


не совсем понятно, что значит сделать устойчивым? на мой взгляд, нужно просто подавать жалобу из groupFrom:

groupFrom crit [] = []
groupFrom crit (x:xs) | not (crit x) = error "ах вы суки эдакие!!!"
groupFrom crit (x:xs) = let (l1:l2) = break crit xs
                        in (x:l1) : groupFrom crit l2



T>3. Написать код печати дерева в исходном виде


print (Tree linenum string subtrees) = string : map ("  "++) (concatMap print subtrees)



T>4. Отфильтровать дерево, оставив только ветви содержащие дубликаты и сами дубликаты.


-- составление списка строк в дереве
strings (Tree _ string subtrees) = string : concatMap strings subtrees

-- получение дубликатов из списка строк
dups = sort >>> group >>> filter (not.null.tail) >>> map head

-- Оставить только часть дерева, содержащую строки из списка strList
onlyFrom strList (Tree linenum string subtrees) = 
  case (string `elem` strList, mapCatMaybes onlyDups subtrees) of
    (False, []) -> Nothing
    (_,     xs) -> Just (Tree linenum string xs)

task4 tree = onlyFrom (dups (strings tree)) tree
Люди, я люблю вас! Будьте бдительны!!!
Re[3]: Мастер-класс по ФП
От: Tonal- Россия www.promsoft.ru
Дата: 08.01.09 16:30
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

Действительно "мастер-класс"!
У меня кода получилось в несколько раз больше.

BZ>не совсем понятно, что значит сделать устойчивым? на мой взгляд, нужно просто подавать жалобу из groupFrom:

BZ>
BZ>groupFrom crit [] = []
BZ>groupFrom crit (x:xs) | not (crit x) = error "ах вы суки эдакие!!!"
BZ>groupFrom crit (x:xs) = let (l1:l2) = break crit xs
BZ>                        in (x:l1) : groupFrom crit l2
BZ>

Я имел в виду, что дерево нужно строить дальше, хотя кончно так и нужно было написать в постановке.
Хотя groupFrom довольно просто изменить под это:
groupFrom crit [] = []
groupFrom crit (x:xs) = 
  let 
    (l1:l2) = break crit xs
    grp x l | not (crit x) = (fst x, "(!)") : x : l
    grp x l = x:l
  in grp x l1 : groupFrom crit l2
... << RSDN@Home 1.2.0 alpha 4 rev. 0>>
Re[14]: Мастер-класс по ФП
От: thesz Россия http://thesz.livejournal.com
Дата: 08.01.09 17:04
Оценка:
T>>The default suggested stack size is 16 kilowords
T>>Оба-на!
К>Ммм, Сергей, думаю стоит внимательней читать, ну какое отношение стэк эмулятора имеет к памяти тех процессов, которые в нём крутятся?

А стек самого процесса, который крутится, где задаётся?

Как я понимаю, он у каждого "легкого процесса" должен быть свой.

К>И чуть ниже смотрим:

К>

К>+h Size
К> Sets the default heap size of processes to the size Size.

К>Вот этот другой (а не +a size) параметр задаёт размер хипов процессов.

Я про стек начал говорить. Стек для каждого из процессов, наверное, в хип не входит.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[15]: Мастер-класс по ФП
От: Курилка Россия http://kirya.narod.ru/
Дата: 08.01.09 17:18
Оценка:
Здравствуйте, thesz, Вы писали:

T>>>The default suggested stack size is 16 kilowords

T>>>Оба-на!
К>>Ммм, Сергей, думаю стоит внимательней читать, ну какое отношение стэк эмулятора имеет к памяти тех процессов, которые в нём крутятся?

T>А стек самого процесса, который крутится, где задаётся?


T>Как я понимаю, он у каждого "легкого процесса" должен быть свой.


А фиг знет где конкретно, тупо просмотром через запуск процесса и вызов process_info/1 выдаёт 8 слов. Но сдаётся мне, что они как раз в те предыдущие 327 как раз входят.
Re[3]: Мастер-класс по ФП
От: Tonal- Россия www.promsoft.ru
Дата: 08.01.09 17:57
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:
T>>3. Написать код печати дерева в исходном виде
BZ>
BZ>print (Tree linenum string subtrees) = string : map ("  "++) (concatMap print subtrees)
BZ>

А как можно изменить этот код чтобы в в начале каждой строки отображался linenum нода?

T>>4. Отфильтровать дерево, оставив только ветви содержащие дубликаты и сами дубликаты.

И опять я не точно выразился.
Дубликатами считаются одинаковые строки одного родителя.
Например:
Животные
  рыбы
    щука
    карась
    щука

После фильтрации должно получится:
Животные
  рыбы
    щука
    щука

Как подправить, сходу не соображу.

Кстати, в моей инсталяции ghc 6.10.1 для винды, в документации нет упоминания mapCatMaybes и описания модуля Maybes тоже нет. Зато есть пустая страница для модуля Maybe
... << RSDN@Home 1.2.0 alpha 4 rev. 0>>
Re[16]: Мастер-класс по ФП
От: thesz Россия http://thesz.livejournal.com
Дата: 08.01.09 18:09
Оценка:
T>>А стек самого процесса, который крутится, где задаётся?
T>>Как я понимаю, он у каждого "легкого процесса" должен быть свой.
К>А фиг знет где конкретно, тупо просмотром через запуск процесса и вызов process_info/1 выдаёт 8 слов. Но сдаётся мне, что они как раз в те предыдущие 327 как раз входят.

Короче говоря, ничего не понятно.

Ты бы провёл эксперимент с 300K отправителей.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[4]: Мастер-класс по ФП
От: Beam Россия  
Дата: 08.01.09 18:46
Оценка:
Здравствуйте, Tonal-, Вы писали:

T>Кстати, в моей инсталяции ghc 6.10.1 для винды, в документации нет упоминания mapCatMaybes и описания модуля Maybes тоже нет. Зато есть пустая страница для модуля Maybe


По-моему функции mapCatMaybes в стандартной библиотеке нет сейчас и не было раньше.
А Maybe перенесли в Data.Maybe. Но модуль Maybe тоже будет работать, так как просто импортирует Data.Maybe
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Best regards, Буравчик
Re[4]: Мастер-класс по ФП
От: BulatZiganshin  
Дата: 08.01.09 19:04
Оценка:
Здравствуйте, Tonal-, Вы писали:

T>А как можно изменить этот код чтобы в в начале каждой строки отображался linenum нода?


show?

T>>>4. Отфильтровать дерево, оставив только ветви содержащие дубликаты и сами дубликаты.

T>Как подправить, сходу не соображу.

строй список дубликатов локально

T>Кстати, в моей инсталяции ghc 6.10.1 для винды, в документации нет упоминания mapCatMaybes и описания модуля Maybes тоже нет. Зато есть пустая страница для модуля Maybe


это из модуля Data.Maybe, я просто держу на диске исходники
Люди, я люблю вас! Будьте бдительны!!!
Re[2]: Мастер-класс по ФП
От: Гест Украина https://zverok.github.io
Дата: 08.01.09 20:29
Оценка:
Здравствуйте, Tonal-, Вы писали:

T>Здравствуйте, BulatZiganshin, Вы писали:

T>Просили продолжения
Автор: Mr.Cat
Дата: 07.01.09
, как обществу такая задачка:


Line = Struct.new(:string, :num, :level)
Leaf = Struct.new(:string, :num, :children)

def read_children(lines, level = 0)
    return [], [] if lines.empty?
    first, *rest = *lines
    case 
        when first.level == level
            children, rest = read_children(rest, level+1)
            first_child = Leaf[first.string, first.num, children]
            sibling, rest = read_children(rest, level)
            return [first_child] + sibling, rest
        when first.level < level
            return [], lines
        when first.level > level
            raise(RuntimeError, "wrong level at line #{first.num}")
    end
end

def print_tree(leafs, level = 0)
    leafs.each do |leaf|
        puts "   " * level + leaf.string
        print_tree(leaf.children, level + 1)
    end
end

def select_duplicates(leafs)
    dup_strings = leafs.
        map{|leaf| leaf.string}.
        group_by{|str| str}.
        select{|str, group| group.size > 1}.
        map{|str, group| str}

    leafs.
        map{|leaf| Leaf[leaf.string, leaf.num, select_duplicates(leaf.children)]}.
        select{|leaf| dup_strings.include?(leaf.string) || !leaf.children.empty?}
end

lines = File.read('tree.txt').split("\n").
    to_enum(:each_with_index).
    map{|ln, idx| Line[ln.strip, idx, ln[/^\s*/].length/2]}

roots, * = read_children(lines)
print_tree(roots)
dups = select_duplicates(roots)
print_tree(dups)
Re[4]: Подумалось...
От: NotGonnaGetUs  
Дата: 09.01.09 13:24
Оценка: 4 (2)
Здравствуйте, Beam, Вы писали:

B>
B>-- универсальная функция, группирует список пар (ключ, значение) по ключу, возвращая список пар (ключ, [значения для этого ключа])
B>-- например groupByFst [(1,2), (1,3), (2,5), (1,4), (2,6)] возвращает [ (1,[2,3,4]), (2,[5,6]) ]
B>-- записываем слово в файл "?.txt" если слово содержит букву ?
B>-- дополнительно слова, длиной 3 пишем во временный файл
B>-- дополнительно слова, начинающиеся с гласной буквы пишем в консоль
NGGU> type Targets = String -> [Target]
NGGU> targets3 :: Targets
B>targets3 word = byContain word ++ byLen3 word ++ byVowel word
B>  where
B>    byContain letters = [File $ s:".txt" | s <- letters]
B>    byLen3 letters | length letters == 3 = [TempFile]
B>                   | otherwise = []
B>    byVowel letters | head letters `elem` ['e','u','i','o','a'] = [Console]
B>                    | otherwise = []
B>


B>Обработку мы настраиваем двумя функциями (передаются в качестве параметра processWord):

B>1. targets — по слову говорит, куда это слово надо записать (в консоль, в конкретный файл, никуда)
NGGU> (Кстати, так задумано, что слово с 3 буквами 'e' попадает в файл с именем 'e' трижды?)
B>2. process — выполняет саму обработку группы слов

Во всех предложенных решениях, кроме, разве что совсем не кастомизируемых, выбор списка для представления элементов группы (а именно его иммутабельность) приводит к необходимости создания конструкции вида [(ID, String)], где ID — идентификатор группы (от вырожденных случаев где ID — имя файла, до сложных — где ID содержит информацию о способе обработки), и необходимости эту конструкцию преобразовывать к виду — [(ID, [String])].
Это иллюстрация того, как выбор "архитектурного решения" (дизайн, если хотите) оказывается взависимости от выбора языка реализации, хотя, казалось бы, такого быть не должно :)

Есть, так же, довольно любопытное мнение, озвучиваемое в л-ре посвящённой ооп, согласно которому, функциональная декомпозиция имеет существенный недостаток перед оо-декопозицей. Утверждается, что при ф-декомпозиции разбиение на подзадачи зависит от выбора "главной функции" системы (в нашей задаче, честно говоря, выбор этой функции очевиден :)) и нет никакой гарантии, что при реализации новой функции получится использовать подзадачи полученные входе первоначального решения -> либо часть функциональности будет повторена, либо потребуется провести декомпозицию всего решения заново, чтобы выделить общие подзадачи...
С этим утверждением можно согласиться, когда речь идёт о "классических" процедурных языках, но в случае с современными функциональными языками, где есть фвп и прочии прелести, можно и поспорить. Чтобы опровергнуть его, нужно привести какие-то доводы в пользу того, что при декомпозиции будут полученны подзадачи имеющие самостоятельное значение для предметной области над которой определена исходная задача (а не для вычислителя). В случае ОО-декомпозиции, этого пытаются достич моделируя сущности/концепции (называйте как хотите) из предметной области в виде объектов и классов объектов, а отнощения между ними — в виде методов классов, статических методов или "синтетических" объектов. В итоге образуется набор "кубиков" из которых затем строится решение конкретной задачи. Поскольку изменения в предметной области случаются реже, чем формулируются новые задачи, вероятность использовать при решении новой задачи существующие "кубики" достаточна велика, что, в каком-то виде, гарантирует устойчивость решения к изменениям в требованиях и упрощение реализации новых требований через повторное использование не только результатов анализа предметной области, но и имеющегося кода. Минусы тут тоже есть:
— во-первых, выделение сущностей и отношений между ними процесс "творческий" и если нет достаточного опыта или таланта, то результат может оказаться плачевным.
— во-вторых, не всегда "изменения в предметной области случаются реже, чем формулируются новые задачи" -> для таких областей нужен другой подход к проектированию.
— в-третьих, существует граница, когда написать решение с нуля проще, чем разбираться во всех имеющихся "кубиках" (это относится не только к ООП, но и к ФП :))
— в-четвёртых, с определённого уровня вложенности подзадачи перестают относиться к предметной области и превращаются в "борьбу" с техническими сложностями/особенностями языка разработки и вспомогательными библиотеками (стандартными/сторонними).
Тем не менее, худо-бедно с этими минусами справиться удаётся.

В случае с ФП всё не так прозрачно. Есть требуется решить "конкретную" задачу, то всё понятно. Задачу крошим на подзадачи и красиво расписываем. Если нужно создать основу для решения родственных задач — тоже понятно — формулируется "конкретная" задача, где описываются вариации, далее задача решается "обычным" путём. Всё хорошо, но только "точки вариации" должны быть описаны _заранее_ (в отличии ОО подхода, когда "все возможные" вариации задач закладываются в модели предметной области (в классах и методах) без попытки перечислить их _все_ явно).
Булат озвучил подход при котором ФЯ используется как средство для описания dsl, на котором затем решается задача. Этот подход отличается от разбиения задачи на подзадачи и может в теории (так же как и ООП — _в теории_ :)) дать гарантии "устойчивости" о которых выше шла речь, т.к. язык предметной области должен, по сути, отражать теже сущности и отношения между ними за которыми гоняется ООП, только в виде отличном от классов и методов (и может быть даже более красивым способом) и убирать на задний план "борьбу" языком и библиотеками. Правда, в этом случае возникает вопрос "как придумать хороший dsl"... но отложим его в сторону до лучших времен

А подумалось вот о чём: может если использовать идею о dsl, то "дизайн" несчастной задачи про слова не зависил бы от языка, как указывалось выше? Надо бы попробовать :)

Итак, нужно выбрать способ формального описания условия задачи, а затем реализовать преобразование формального описания в описание на яп.
Отталкиваться будем от того, что критерий разбивки слов на группы часто меняется, поэтому dsl должен позволять быстро реализовывать новые варианты. Можно сделать так:

StartWith "a" -> WriteToFile "a"
StartWith "b" -> WriteToFile "b"
...
StartWith "z" -> WriteToFile "z"
Сontains "c" -> WriteToFile "Contains 'c | d'"
Сontains "d" -> WriteToFile "Contains 'c | d'"
StartWith "aaa" -> WriteToFile "aaa"
... 
StartWith "paa" -> WriteToConsole "test", WriteToFile "paa"
StartWith "pab" -> WriteToFile "aaa"
...
StartWith "zzz" -> WriteToFile "zzz"


Очевидно, что требуются примитивы для упрощения ввода "программы":

StartWith x -> WriteToFile x, x in ["a" .. "z"] 

Сontains "c" | Сontains "d" -> WriteToFile "Contains 'c | d'"

Match (wordPrefix 3) | "paa"  -> WriteToConsole "debug", WriteToFile "paa"  
                     | prefix -> WriteToFile prefix

Почесав репу, можно добавить нотацию для конфигурирования процесса группировки:

StartWith x -> WriteToFile x {unique: true}, x in ["a" .. "z"] 
-- ^^ в файл пишутся только уникальные строки (дубликаты игнорируются и в другие группы не попадают)
 
Сontains "c" | Сontains "d" {unique: true} -> WriteToFile "Contains 'c | d'"  
-- ^^ матчатся только уникальные строки (дубликаты не матчатся и могут попасть в другие группы)

Match (wordPrefix 3) | "paa"  -> WriteToConsole "debug", WriteToFile "paa"  
                     | prefix -> WriteToFile prefix

Думаю, что такой-же синтаксис можно было бы, чуть-чуть изменив, свести к синтаксису хаскелл. А как насчёт ООЯ?

В java получилось бы что-то такое:
b = new RuleBuilder()
for(String x : new Range("a", "z")) {
    b.addRule(new StartWith(x), 
              new WriteToFile(x).unique(true));
}

b.addRule(new Or(new Contains("c"), new Contains("d")).unique(true), 
          new WriteToFile("Contains 'c | d'"));

b.addRule(new WordPrefixRule(3) {
              Action createDefaultAction(String prefix) { 
                     return new WriteToFile(prefix); 
              }
          }.add("paa", new WriteToConsole("debug"), new WriteToFile("paa")));

b.process(theData);


Конечному пользователю, конечно, не отдашь, но если бы была выгода от использования текстового dsl, то от этого чуда её тоже можно было бы поиметь.

B>На самом деле, то же можно повторить и в ООП :) Разный подход будет в "настройке".

B>Думаю решение на ООП будет выглядеть чуть по сложнее, т.к., на мой взгляд, функцию легче охватить взглядом и понять, чем класс ООП.
B>Не говоря уже о добавлении нескольких классов / интерфейсов.

От смотрящего многое зависит. Имхо, если классы/интерфейсы не с неба брались, то ситуация аналогична ситуации со скобками в лиспе: кто-то без них жить не может, кто-то принципиально не перевариавает :)
Re: Мастер-класс по ФП
От: MasterZiv СССР  
Дата: 09.01.09 15:14
Оценка: -1
BulatZiganshin пишет:

> итак, попробуйте решить эти задачи:

>
> 1) есть список слов. надо записать в файл "a" все слова, начинающиеся на
> букву 'a', в файл "b" — слова на 'b' и т.д. вплоть до z

Я что=то не вижу тут особенно функционального программирования.
Декларативное — при возможности делать destructuring строк — может быть.
Тут даже функций высших порядков не применить, кажется.

;;;; -*- Mode: Lisp; Syntax: Common-Lisp; Package: fp-train-1 -*-

(defpackage #:fp-train-1 (:use :cl))

(in-package #:fp-train-1)

(defun 1-st-letter (word)
   (cond ((symbolp word) (char (symbol-name word) 0))
    ((stringp word) (char word 0))
    ((characterp word) word)
    (t word)))

(let ((files nil))
   (defun letter-file (letter)
     (let ((file (cdr (assoc letter files))))
       (if file
      file
      (let ((file (open (string letter) :direction :output)))
        (setf files (acons letter file files))
        file))))
   (defun finish ()
     (mapc (lambda (e) (close (cdr e))) files)))

(defun cast-words (word-list)
   "Casts all words in WORD-LIST by files named A, B, ... Z according to their 
first letter"
   (unwind-protect
        (mapc
    (lambda (word)
      (format (letter-file (1-st-letter word)) "~A~%" word))
    word-list)
     (finish)))
Posted via RSDN NNTP Server 2.1 beta
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.