Lisp - [преобразование КНФ в правильную КНФ]

ThatsMe

народ, помогите написать эту програмку. или может у кого завалялась. поидее для знающих людей должно быть легко. времени сейчас позарез - разбираться некогда. напишите в приват какое вознаграждение вас устроит
зы ДНФ - правильная, если каждая ее элементарная конъюнкция не содержит повторных вхождений одной переменной.

Ivan8209

Каково исходное представление данных?
---
...Я работаю антинаучным аферистом...

ThatsMe

представление исходных данных и вид результирующих данных - на выбор.
внутреннее представление обрабатываемых символьных выражений - тоже
("через задницу" наверное не стоит)

Ivan8209

Могу подсказать, как ваять, либо могу сваять сам, но на Схеме.
Могу потом перевести и на Елисп, устанавливать Common не хочу.
На выбор.
Есть прямой способ, без оптимизаций и прочих наворотов.
---
...Я работаю антинаучным аферистом...

ThatsMe

Если сделаешь с комментами будет супер. Елисп подойдет , только расшарь его потом плиз.

Ivan8209

Через полчаса будет.
---
...Я работаю...

Ivan8209


(define (uniq lst)
(if (null? lst) lst
(let ulst (uniq (cdr lst
(if (member (car lst) ulst) ulst lst
(uniq '(a b c d e f
(uniq 'a a) (b b) (c c
(uniq '(a a b c a d b c
(uniq '(a (a a) a (a a) (a a) a
(define (check-var-i var df)
(and (member var df) (member (list 'not var) df
(define (check-var var df)
(if (and (list? var) (eqv? 'not (car var
(check-var-i (cadr var) df)
(check-var-i var df
(display "check-var") (newline)
(check-var 'a '(a b c
(check-var 'a 'not a) b c
(check-var 'a 'not a) b a c
(define (simplify-disj df)
(cond null? df) df)
equal? '(#f)
(uniq (map check-var df
(make-list (length df) df
df)
(else #t
(display "simplify-disj") (newline)
(simplify-disj '(a
(simplify-disj '(a b c d
(simplify-disj 'not a) b (not c) d
(simplify-disj 'not a) b (not c) c d
(simplify-disj '(a b c a (not c) b a d
(newline)
(define (filter p l)
(if (null? l) l
(if (p (car l
(cons (car l) (filter p (cdr l
(filter p (cdr l
(lambda (x) (not (eqv? #t x
(define (not-#t? x) (not (eqv? #t x
(define (simplify-conj cf)
(if (member #f cf) #f
(let pcnf
(uniq (map simplify-disj (filter not-#t? cf
(if (member #f pcnf) #f
(filter not-#t? pcnf
(simplify-conj
'a b c d)
(a (not a) b c d)
#f
(a c d)
(a b c d
(simplify-conj
'a b c d)
(a (not a) b c d)
(a c d)
(a b c d

Scheme R5.
Проверялось на Guile:

cat file.scm | guile

Вопросы?
---
...Я работаю антинаучным аферистом...

ThatsMe

пока ничего не понятно
книжку по лиспу сейчас возьму и буду врубаться

Ivan8209

Если вопрос стоит так, то книжку надо брать по истинному лиспу --- Схеме.
http://schemers.org/
---
...Я работаю антинаучным аферистом...

ThatsMe

thx тебе огромный, но ты не мог бы хоть немного комментариев поставить - где там что происходит?

ThatsMe

брб... lisp <> scheme?
\\ и инета сейчас нет, чтоб почитать тот сайт

Ivan8209


;; -*- coding: cyrillic-alternativnyj; -*-
; $Id: knf.scm,v 1.2 2006/05/17 13:39:48 user Exp $
; Нам понадобится работать со списком, как с множеством,
; то есть, надо исключать повторные вхождения.
(define (uniq lst)
  (if (null? lst) lst
     (let ulst (uniq (cdr lst
(if (member (car lst) ulst) ulst lst
; Проверка:
(uniq '(a b c d e f
(uniq 'a a) (b b) (c c
(uniq '(a a b c a d b c
(uniq '(a (a a) a (a a) (a a) a
; Проверяем вхождение переменной и её отрицания в дизъюнктивную форму.
(define (check-var-i var df)
  (and (member var df) (member (list 'not var) df
; Поскольку переменная может встретиться в виде отрицания,
; возможно, потребуется снять объемлющее "not"
(define (check-var var df)
  (if (and (list? var) (eqv? 'not (car var
     (check-var-i (cadr var) df)
     (check-var-i var df
; Проверка:
(check-var 'a '(a b c
(check-var 'a 'not a) b c
(check-var 'a 'not a) b a c
(check-var '(not a) 'not a) b a c
; Упрощение ДФ: исключение повторов, проверка на то,
; что она не сводится к тождественной.
(define (simplify-disj df)
  (cond null? df) df)
equal? '(#f)
(uniq (map check-var df
(make-list (length df) df
df)
(else #t
(begin (display "Testing simplify-disj") (newline
(simplify-disj '(a
(simplify-disj '(a b c d
(simplify-disj 'not a) b (not c) d
(simplify-disj 'not a) b (not c) c d
(simplify-disj '(a b c a (not c) b a d
(newline)
; Выборка членов списка, удовлетворяющих условию p.
(define (filter p l)
  (if (null? l) l
     (if (p (car l
(cons (car l) (filter p (cdr l
(filter p (cdr l
(define (not-#t? x) (not (eqv? #t x
; Упрощение конъюнктивной формы:
; отсечение тождественно ложных и тождественно истинных членов,
; упрощение входящих дизъюнктивных форм, устранение повторов.
(define (simplify-conj cf)
  (if (member #f cf) #f
     (let pcnf
(uniq (map simplify-disj (filter not-#t? cf
(if (member #f pcnf) #f
(filter not-#t? pcnf
; Проверка
(simplify-conj
 'a b c d)
   (a (not a) b c d)
   #f
   (a c d)
   (a b c d
(simplify-conj
 'a b c d)
   (a (not a) b c d)
   (a c d)
   (a b c d

---
...Я работаю...

Ivan8209

Scheme <- T = True Lisp
Тут все слова понятны, а на каком диалекте шепчешь ты, я не знаю,
да и ты сам --- не сказал.
---
...Я работаю антинаучным аферистом...

vook

Я бы написал (на Common Lisp но я не знаю что такое КНФ

Ivan8209


;; -*- coding: cyrillic-alternativnyj; -*-
; $Id: knf.el,v 1.3 2006/05/17 14:18:22 user Exp $
; Нам понадобится работать со списком, как с множеством,
; то есть, надо исключать повторные вхождения.
(defun uniq (lst)
(if (null lst) lst
(let ulst (uniq (cdr lst
(if (member (car lst) ulst) ulst lst
; Проверка:
(uniq '(a b c d e f
(uniq 'a a) (b b) (c c
(uniq '(a a b c a d b c
(uniq '(a (a a) a (a a) (a a) a
; Проверяем вхождение переменной и её отрицания в дизъюнктивную форму.
(defun check-var-i (var df)
(and (member var df) (member (list 'not var) df
; Поскольку переменная может встретиться в виде отрицания,
; возможно, потребуется снять объемлющее "not"
(defun check-var (var df)
(if (and (listp var) (eq 'not (car var
(check-var-i (cadr var) df)
(check-var-i var df
; Проверка:
(check-var 'a '(a b c
(check-var 'a 'not a) b c
(check-var 'a 'not a) b a c
(check-var '(not a) 'not a) b a c
(defun maplist (f l)
(if (null l) l
(cons (apply f (list (car l (maplist f (cdr l
(defun mapl (f l)
(if (member nil l) nil
(cons (apply f (maplist 'car l
(mapl f (maplist 'cdr l
(defun map (f &all l) (mapl f l
; Упрощение ДФ: исключение повторов, проверка на то,
; что она не сводится к тождественной.
(defun simplify-disj (df)
(cond null df) df)
equal '(nil)
(uniq (mapl 'check-var (list df
(make-list (length df) df
df)
(t t
(simplify-disj '(a
(simplify-disj '(a b c d
(simplify-disj 'not a) b (not c) d
(simplify-disj 'not a) b (not c) c d
(simplify-disj '(a b c a (not c) b a d
(newline)

; Выборка членов списка, удовлетворяющих условию p.
(defun filter (p l)
(if (null l) l
(if (apply p (list (car l
(cons (car l) (filter p (cdr l
(filter p (cdr l
(defun not-t (x) (not (eq t x
; Упрощение конъюнктивной формы:
; отсечение тождественно ложных и тождественно истинных членов,
; упрощение входящих дизъюнктивных форм, устранение повторов.
(defun simplify-conj (cf)
(if (member nil cf) nil
(let pcnf
(uniq (mapl 'simplify-disj (list (filter 'not-t cf
(if (member nil pcnf) nil
(filter 'not-t pcnf
; Проверка
(simplify-conj
'a b c d)
(a (not a) b c d)
nil
(a c d)
(a b c d
(simplify-conj
'a b c d)
(a (not a) b c d)
(a c d)
(a b c d

---
INSTITUTE's Name Shows That It's Totally Unrelated To Emacs.

ThatsMe

muchas gracias

Ivan8209

Исправления.

===================================================================
RCS file: RCS/knf.scm,v
retrieving revision 1.2
diff -u -r1.2 knf.scm
--- knf.scm 2006/05/17 13:39:48 1.2
+++ knf.scm 2006/05/17 17:48:09
@@ -1,5 +1,5 @@
;; -*- coding: cyrillic-alternativnyj; -*-
-; $Id: knf.scm,v 1.2 2006/05/17 13:39:48 user Exp $
+; $Id: knf.scm,v 1.4 2006/05/17 17:46:17 user Exp $

; Нам понадобится работать со списком, как с множеством,
; то есть, надо исключать повторные вхождения.
@@ -31,15 +31,17 @@
(check-var 'a 'not a) b a c
(check-var '(not a) 'not a) b a c

+; Проверка на то, что все члены списка равны заданному.
+(define (all? el lst) (equal? (list el) (uniq lst
+
; Упрощение ДФ: исключение повторов, проверка на то,
; что она не сводится к тождественной.
(define (simplify-disj df)
- (cond null? df) df)
- equal? '(#f)
- (uniq (map check-var df
- (make-list (length df) df
- df)
- (else #t
+ (cond
+ all? #f df) #f)
+; member #t df) #t)
+ all? #f (map check-var df (make-list (length df) df df)
+ (else #t

(begin (display "Testing simplify-disj") (newline

@@ -48,14 +50,14 @@
(simplify-disj 'not a) b (not c) d
(simplify-disj 'not a) b (not c) c d
(simplify-disj '(a b c a (not c) b a d
+(simplify-disj '(#f #f #f
(newline)

; Выборка членов списка, удовлетворяющих условию p.
(define (filter p l)
- (if (null? l) l
- (if (p (car l
- (cons (car l) (filter p (cdr l
- (filter p (cdr l
+ (cond null? l) l)
+ p (car l (cons (car l) (filter p (cdr l
+ (else (filter p (cdr l

(define (not-#t? x) (not (eqv? #t x

@@ -82,3 +84,11 @@
(a (not a) b c d)
(a c d)
(a b c d
+
+(simplify-conj
+ 'a b c d)
+ (a (not a) b c d)
+ (a c d)
+ (#f #f)
+ (a c d c)
+ (a b c d

---
"Потому что Аллах не ведёт людей неверных."

enochka1145

КОНТРА выдал код. Что, что, чёрт возьми, случилось?! Он что, жениться собрался?
Ну теперь-то я знаю, как выглядит удобный, читабельный и интуитивно-очевидный код, которого так не хватает всем этим ламерским ООП-языкам.

Ivan8209

Схема --- это полноценный истинный Лисп.
Емакс-лисп --- это полноценный Лисп.
Да, в Емакс-лиспе, в силу его особенностей, нет map.
В какой библиотеке находится filter, я не помню, а потому просто доопределил.
Точно так же я не заморачивался и с другими вещами,
поскольку было требование побыстрее, а не попроще и получше.
Вот когда стандарт Common LISP будет помещаться на 50 страницах,
тогда вернёмся к обсуждению его достоинств, а покуда это не так,
Common LISP будет похуже фортрана, поскольку последний превосходит Common LISP
как по простоте, так и по функциональности стандартного кода.
Мало того, кто-кто, а ты вообще молчал бы, что-то от тебя решения не увидели --- в кусты спрятался.
---
...Я работаю антинаучным аферистом...

Landstreicher

Ну теперь-то я знаю, как выглядит удобный, читабельный и интуитивно-очевидный код, которого так не хватает всем этим ламерским ООП-языкам
Чего смешного то? Вполне понятный и легко читаемый код. На C++ многие гораздо хуже пишут.

vook

Мало того, кто-кто, а ты вообще молчал бы, что-то от тебя решения не увидели --- в кусты спрятался.
Просто я так и не понял в чем заключается задача

Ivan8209

Тем хуже для тебя.
---
...Я работаю антинаучным аферистом...

kokoc88



Чего смешного то? Вполне понятный и легко читаемый код. На C++ многие гораздо хуже пишут.
Утверждается, что код может прочитать только человек, очень хорошо знакомый с этим языком.

(simplify-conj
'a b c d)
(a (not a) b c d)
nil
(a c d)
(a b c d

Вот это мне НИ О ЧЁМ не говорит, то есть вообще. Даже плохо написанный код на С++ содержал бы какие-то слова, которые могли бы натолкнуть на мысль. А тут полный ноль. И не надо орать "ботай матчасть", как некоторые любят делать. Приведённый код неудобно читать.

Marinavo_0507

> Даже плохо написанный код на С++ содержал бы какие-то слова
В данном случае - нет
Ну то есть, слово SimplifyConj содержал бы тоже

kokoc88

Ну там внутри бы были намёки, как происходит упрощение конъюнкции. Тут я пока что даже представить не могу, как.

Ivan8209

> Даже плохо написанный код на С++ содержал бы какие-то слова, которые могли бы натолкнуть на мысль.
Слова main, do, while, if, else и return наталкивают просто на офигенные мысли.
А уж про обозначение "==" я вообще молчу.
---
...Я работаю антинаучным аферистом...

Ivan8209

> внутри бы были
Предъяви код.
---
"Истина всегда конкретна."

kokoc88



Слова main, do, while, if, else и return наталкивают просто на офигенные мысли.
А уж про обозначение "==" я вообще молчу.
Главное, что они вообще наталкивают на мысли. Где начинается твоя программа и как она начинается вообще нельзя понять. А if/else наталкивают на вполне определённые мысли. Про "==" я уже давно писал, что все языки определяют присваивание и сравнение по-своему, в паскале, например, есть ":=".

kokoc88



Предъяви код.
Помнишь, что ты отвечал, когда я тебя просил предъявить код на ЛИСПе для кучи задач, в которые ты лез спорить? А сейчас тебе за год попалась-таки задача, которая хорошо ложится на фя, и ты начинаешь петушиться.

Ivan8209

> Где начинается твоя программа и как она начинается вообще нельзя понять.
Программа начинается с начала и заканчивается концом.
Вообще же, умение дифференцировать простые линейные формы
должно было быть выработано ещё в старшей группе детского сада.
> А if/else наталкивают на вполне определённые мысли.
Прикинь, слова "define," "map," "filter" тоже наталкивают на определённые мысли!
---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."

Ivan8209

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

kokoc88



Вообще же, умение дифференцировать простые линейные формы
должно было быть выработано ещё в старшей группе детского сада.
Давай поступим вот так: придём в старшую группу детского сада и всех детишек попросим (дословно) "продифференцировать простые линейные формы". Как ты думаешь, что после этого будут думать детишки про дядю контру?

kokoc88



У тебя есть преимущество в виде уже работающего кода,
можешь воспользоваться этим --- просто перевести со Схемы на Си.
История знает случаи, когда у тебя тоже было такое "преимущество". Естественно, для человека, который не знает ЛИСПа, это вовсе не преимущество. Если бы я и стал сейчас писать код на Си, то сначала бы прочитал про алгоритм решения поставленной задачи.

Ivan8209

> История знает случаи, когда у тебя тоже было такое "преимущество".
Нет.
Таких случаев пока что не наблюдалось: насильники пишут
в стиле "настоящих программистов", с циклами на пять страниц и т.п.
Когда ты мне покажешь прилично написанную программу,
то есть состоящую из подпрограмм длиной не более 6-8 строк,
тогда и будешь говорить о читаемости.
---
"Мы диалектику учили не по Гегелю."

psihodog

что такое правильная КНФ скажи, а то там не написано.
тогда может чё-нть сваяю.

Ivan8209

Математик?
> ДНФ - правильная, если каждая ее элементарная конъюнкция
> не содержит повторных вхождений одной переменной.
---
...Я работаю антинаучным аферистом...

psihodog

Химик?
> ДНФ - правильная...
vs
> Что такое правильная КНФ?

Marinavo_0507

> Тут я пока что даже представить не могу, как.
Твои проблемы, что ты не на ту строку посмотрел.
У меня то же самое, когда код на C++ с шаблонами наблюдаю - не знаю, куда смотреть, чтобы понять что-то.

kokoc88



Твои проблемы, что ты не на ту строку посмотрел.
Я честно посмотрел всю программу. И даже нашёл где она вроде бы начинается и что-то печатает на экран.

Marinavo_0507

> И даже нашёл где она вроде бы начинается
Начинается она в начале, как уже было сказано.
> что-то печатает на экран
Печатается на экран тестовый пример, разумеется. А что ещё могло бы?

kokoc88

Кстати, вот пример что незнающий человек может что-то понять в Си.

Хотя пример неточный, может Lynn и LISP поймёт.

kokoc88

Не важно, что могло. Мой пост был о том, что я просмотрел всю программу.

enochka1145

Давай поступим вот так: придём в старшую группу детского сада и всех детишек попросим (дословно) "продифференцировать простые линейные формы". Как ты думаешь, что после этого будут думать детишки про дядю контру?
"продифференцировать простые линейные формы" - имеется в виду отличать треугольник от квадрата и т.д. Некоторые просто физиологически не могут вести себя (в т.ч. говорить) по-человечески.

kokoc88



"продифференцировать простые линейные формы" - имеется в виду отличать треугольник от квадрата и т.д. Некоторые просто физиологически не могут вести себя (в т.ч. говорить) по-человечески.
Смысл моего поста не в этом. Просто тут вся контора смеялась.

Ivan8209

> Химик?
Физик.
> ДНФ - правильная...
vs
> Что такое правильная КНФ?
Мышление напрочь отбило?
Есть такой способ, по аналогии.
---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."

Marinavo_0507

> Мой пост был о том, что я просмотрел всю программу.
Посимвольно? Я так тоже C++ могу просматривать, это не поможет понять, что там делают эти шаблоны.

kokoc88



Посимвольно? Я так тоже C++ могу просматривать, это не поможет понять, что там делают эти шаблоны.
А я и не утверждаю, что всё будет понятно. А поняв, что такое шаблоны в одном языке, можно потом понять, что они делают и как работают в других языках. Впрочем, ФЯ тоже должны быть похожи в этом плане.

Ivan8209

Очевидно, что ты так и не понял, что такое функция.
---
...Я работаю антинаучным аферистом...

psihodog

Мышление напрочь отбило?
Есть такой способ, по аналогии.
Как показывает практика придумывать определения "по аналогии", особо не разбираясь в предметной области может быть чревато.

kokoc88



Очевидно, что ты так и не понял, что такое функция.
Что такое функция в твоём понимании?

Ivan8209

Ты предлагаешь мне объяснять, что такое дизъюнкция,
что такое конъюнкция, и почему есть двойственность?
---
...Я работаю антинаучным аферистом...

Ivan8209

Однозначная зависимость.
---
...Я работаю антинаучным аферистом...

kokoc88



Однозначная зависимость.
Да, ты реально любишь, когда люди тебя не понимают. Проблемы с самоутверждением, что ли? Выражайся яснее, чтобы смертным, типа меня, было понятно. Зависимость чего от чего? Результата от аргументов?

Ivan8209

> Зависимость чего от чего? Результата от аргументов?
У тебя явные проблемы с мышлением.
А что ещё может быть?
Сравни "А есть функция Б и В" и "А однозначно зависит от Б и В."
---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."

kokoc88

Почему вот это
(simplify-conj
 'a b c d e e e
выдаёт результат
guile> a b c d e e e
 
Написано, что повторных вхождений быть не должно. Или я не правильно понял формат входных данных?
Вот ещё не ясно, такое выражение
(simplify-conj
'(
(a b c d e)
(abc)
(abc)
)
)
выдаёт
a b c d e) (abc) (abc
в то время как
(simplify-conj
'(
(abc)
(abc)
)
)
выдаёт
abc

psihodog

Ты предлагаешь мне объяснять, что такое дизъюнкция,
что такое конъюнкция, и почему есть двойственность?
Какая ещё двойственность?
Ты мне предлагаешь рассказать тебе основы мат.логики?

Ivan8209

Fix:

(define (uniq lst)
(if (null? lst) lst
(let ulst (uniq (cdr lst
(if (member (car lst) ulst) ulst
(cons (car lst) ulst


(define (simplify-disj df)
(cond
all? #f df) #f)
; member #t df) #t)
all? #f (map check-var df (make-list (length df) df
(uniq df
(else #t

А ещё элементарные дизъюнкции надо отсортировать.
---
...Я работаю...

Andbar

эти все поправки - улучшения работы уже правильной программы или же это багофиксы?

kokoc88

Смотря как послностью сформулировать задачу. Ещё надо добавить код, чтобы (a b c) и (c a b) считались одинаковыми и оптимизировались.

kokoc88

Предъяви код.
Стёрто, чтобы не наезжали без повода.

psihodog

Ну-ка предъявите ОО решение на приплюсях, яве или чём ещё.
Python:
 
def simplify_disj(disj):
ctos= (None, '', '!')
els= {}
for el in disj.split(' '):
if el[0] == '!':
el= el[1:]
vl= 2
else: vl= 1
els[el]= els.get(el, 0) | vl
return ' '.join(ctos[els[el]]+el for el in sorted(els.iterkeys if els[el] != 3)
def simplify_cnf(cnf):
return ''.join('('+disj+')' for disj in set(simplify_disj(disj) for disj in cnf[1:-1].split(''.difference(['']
# Unit testing section:
if __name__ == '__main__':
totest= ("(a b !c)",
"(a a b !c !a b)",
"(a a !a)",
"(a a !aa b)",
"(a ba b)",
"(a b a dd b c !a)")
for cnf in totest:
print cnf, '->', simplify_cnf(cnf)

Marinavo_0507

> Вот решение в лоб, просто я с работы и уставший.
> Парсер строки и преобразование тут в одном флаконе.
Про модульность на вашей работе не слышали?

Landstreicher

> Утверждается, что код может прочитать только человек, очень хорошо знакомый с этим языком.
Достаточно понимать самые основы Lisp чтобы понять код. При условии понимания синтаксиса --- код тривиален. Я бы разделил сложность кода на сложность синтаксическую и алгоритмическую. Здесь алгоритмическая близка к нулю — код простой.
> Вот это мне НИ О ЧЁМ не говорит, то есть вообще. Даже плохо написанный код на С++ содержал бы какие-то слова, которые могли бы натолкнуть на мысль.
Несогласен. Вот например, сравни с таким кодом (boost_concept_check.h из стандартной поставки gcc 4.0.3)

template <class _ReversibleContainer>
struct _Mutable_ReversibleContainerConcept
{
typedef typename _ReversibleContainer::iterator _Iterator;
typedef typename _ReversibleContainer::reverse_iterator _Reverse_iterator;
void __constraints {
__function_requires<_ReversibleContainerConcept<_ReversibleContainer> >
__function_requires<
_Mutable_ForwardContainerConcept<_ReversibleContainer> >
__function_requires<_Mutable_BidirectionalIteratorConcept<_Iterator> >
__function_requires<
_Mutable_BidirectionalIteratorConcept<_Reverse_iterator> >
_Reverse_iterator __i = __c.rbegin;
__i = __c.rend;
}
_ReversibleContainer __c;
};

Человек не рюхающий C++ не поймет тут ничего.
> А тут полный ноль. И не надо орать "ботай матчасть", как некоторые любят делать. Приведённый код неудобно читать
Код просто не похож на C. И все. Других особенностей у него нет.
Почему все так бояцца скобочной записи? IMHO очень простая вещь.

kokoc88

Про модульность на вашей работе не слышали?
Я написал эту функцию за 10 минут просто чтобы показать, что написать вообще можно.

Ivan8209

> Вот решение в лоб, просто я с работы и уставший.
"Real programmer can program FORTRAN in any language."
Если ты способен писать такое, то принимать от тебя ссылки на "уставший" --- преступление.
> Работает в два раза быстрее
А это вообще не рассматривается, "machine cycles are cheap."
---
...Я работаю антинаучным аферистом...

Marinavo_0507

> Я написал эту функцию за 10 минут просто чтобы показать, что написать вообще можно.
Конечно можно, только не модульно и непонятно. Кто бы сомневался.
К вопросу о словах: в твоём коде спецсимволов больше, чем слов.

kokoc88

Если ты способен писать такое, то принимать от тебя ссылки на "уставший" --- преступление.
В чём твои проблемы? Я пришёл с работы и накатал код, не вижу в этом ничего плохого. Впрочем, не стоило этого делать конктретно в этом топике.
А это вообще не рассматривается, "machine cycles are cheap."

Да что ты говоришь?..

kokoc88

#include "stdafx.h"
#include <vector>
#include <string>
#include <set>
#include <iostream>
#include <map>
#include <time.h>
class CSimpleDisj
{
std::map<std::string, bool> m_mapVars;
typedef std::map<std::string, bool>::iterator TIterator;
typedef std::pair<std::string, bool> TPair;
public:
bool operator < (const CSimpleDisj& rfSrc) const
{
return m_mapVars < rfSrc.m_mapVars;
}
bool AddVariable(std::string rfVarName, bool bNotFlag)
{
TIterator iter = m_mapVars.find(rfVarName);
if (iter == m_mapVars.end
{
m_mapVars.insert(TPair(rfVarName, bNotFlag;
return true;
}
else
if (iter->second != bNotFlag)
{
//std::cout << "Disj rejected." << std::endl;
m_mapVars.clear;
return false;
}
else
return true;
}
bool HasVariables
{
return m_mapVars.size > 0;
}
void Clear
{
m_mapVars.clear;
}
void DebugPrint
{
for (TIterator iter = m_mapVars.begin; iter != m_mapVars.end; )
{
std::cout << (iter->second ? "not " : "") << iter->first;
iter++;
if (iter != m_mapVars.end
std::cout << ' ';
}
}
};
class CConjDisj
{
std::set<CSimpleDisj> m_setDisj;
typedef std::set<CSimpleDisj>::iterator TIterator;
CSimpleDisj m_cTempDisj;
bool m_bSkipDisj;
public:
void AddVariable(std::string& rfVarName, bool bNotFlag)
{
if (m_bSkipDisj)
return;
//std::cout << "Variable: " << (bNotFlag ? "not " : "") << rfVarName << std::endl;
m_bSkipDisj = !m_cTempDisj.AddVariable(rfVarName, bNotFlag);
}
void EndOfDisj
{
m_bSkipDisj = false;
if (m_cTempDisj.HasVariables
{
TIterator iter = m_setDisj.find(m_cTempDisj);
if (iter == m_setDisj.end
{
//std::cout << "New disj added." << std::endl;
m_setDisj.insert(m_cTempDisj);
}
else
{
//std::cout << "Same disj, rejected." << std::endl;
}
m_cTempDisj.Clear;
}
}
CConjDisj : m_bSkipDisj(false)
{
}
void DebugPrint
{
for (TIterator iter = m_setDisj.begin; iter != m_setDisj.end; iter++)
{
std::cout << '(';
iter->DebugPrint;
std::cout << ')' << std::endl;
}
}
};
void ParseString(const char* strData, CConjDisj& rfResult) throw(std::runtime_error)
{
int nBracerFlag = 0;
std::string strToken;
bool bNotFlag = false;
for (const char* c = strData; *c != '\0'; c++)
{
switch (*c)
{
case '(':
if (++nBracerFlag > 1)
throw std::runtime_error("Parse error.");
break;
case ')':
if (--nBracerFlag < 0 || bNotFlag)
throw std::runtime_error("Parse error.");
case ' ':
if (strToken.length > 0)
{
if (strToken == "not")
bNotFlag = !bNotFlag;
else
{
rfResult.AddVariable(strToken, bNotFlag);
bNotFlag = false;
}
strToken.clear;
}
if (nBracerFlag == 0)
rfResult.EndOfDisj;
break;
default:
if (nBracerFlag != 1)
throw std::runtime_error("Parse error.");
if *c < 'a' || *c > 'z') && (*c < 'A' || *c > 'Z'
throw std::runtime_error("Invalid character.");
strToken += *c;
}
}
}
int main(int argc, char* argv[])
{
__time64_t nTime = _time64(NULL);
const char* strConjDisj = "(a b c) (a b cd e f e e) (c b a) (a b c) (a b cd e f e e)"
"(a b not c not not c k) (e a b cd e f) (a not not c b b) (not k k)";
try
{
for (int i = 0; i < 100000; i++)
{
CConjDisj cConjDisj;
ParseString(strConjDisj, cConjDisj);
//cConjDisj.DebugPrint;
}
}
catch(std::runtime_error cError)
{
std::cout << "Error: " << cError.what << std::endl;
}
std::cout << "All done, time: " << _time64(NULL)-nTime << std::endl;
std::cin.get;
return 0;
}

Ivan8209

Определение ParseString перекрывает пределы читаемости, по меньшей мере, в два раза.
То же --- с main.
В общем, насильники ещё раз показали, как они понимают читаемость.
---
...Я работаю антинаучным аферистом...

kokoc88

В общем, насильники ещё раз показали, как они понимают читаемость.

Да, извини, забыл написать p... Жалко, что ты без этого никак не можешь читать код.

kokoc88

Почему все так бояцца скобочной записи? IMHO очень простая вещь.
Я не боюсь и даже не буду спорить, что она простая. Но прочитать её занимает просто уйму времени. Потому что кроме скобок других разделителей нет.
Достаточно понимать самые основы Lisp чтобы понять код.
Да код-то я в итоге смогу понять. Синтаксис. Но вот разворачивать в уме семантику - это нечто нетривиальное. Плюс ко всему, большая часть задач вовсе не для ЛИСПа. Думаю, что у него вполне ограниченная область применения, в которой он тихонечко рулит. Глобальный спор о том, что мирового господства у ФЯ нет и быть не может. Никогда. Только кто-то никак с этим не смирится.

Marinavo_0507

Ну и в каком месте здесь происходит преобразование?
Насколько я смог осилить эту мешанину из неприличных символов, ни в каком - перемешано со служебным кодом. Этого последнего также слишком много.

Dasar

> Почему все так бояцца скобочной записи? IMHO очень простая вещь.
потому что она тупая, а не простая.
я понимаю - почему компьютер работает только с ноликами/единичками, или только со скобочками - он тупой и ему это положено.
но я не понимаю, почему такой же тупости должен придерживаться и человек, который априори может работать и с намного более сложными вещами.

kokoc88

Ну и в каком месте здесь происходит преобразование?
Насколько я смог осилить эту мешанину из неприличных символов, ни в каком - перемешано со служебным кодом. Этого последнего также слишком много.
Просто тебя в детском саду не научили дифферинцировать простые линейные формы.

Marinavo_0507

Не вижу класса/метода/функции, в названии которой были бы слова, означающие, что именно там определено преобразование.

kokoc88

Не вижу класса/метода/функции, в названии которой были бы слова, означающие, что именно там определено преобразование.
Скопируй в ноутпад и переименуй ParseString в ParseStringAndStoreToResultSimplified и AddVariable в AddVariableAndSimplify.

Ivan8209

> ParseStringAndStoreToResultSimplified
В курсе, что "упростить" и "сохранить" --- это два разных глагола?
А теперь подумай, что лучше отражает действительность
"(define result (simplified conj-form" или твоё "ParseStringAndStoreToResultSimplified".
---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."

Marinavo_0507

> ParseString в ParseStringAndStoreToResultSimplified
значит, модульность не появилась
> AddVariable в AddVariableAndSimplify
смесь собственно преобразования с несущественными причудами реализации
никакой абстракции данных
где подпрограмма, к которой на входе одна форма, а на выходе - она же после преобразования?

Ivan8209

> почему такой же тупости должен придерживаться и человек
Скажи, почему ты программируешь не на естественном языке?
---
...Я работаю антинаучным аферистом...

Dasar

> Скажи, почему ты программируешь не на естественном языке?
потому что компьютер тупой и не понимает естественный язык.

Dasar

> где подпрограмма, к которой на входе одна форма, а на выходе - она же после преобразования?
так устроит?

using System;
using System.Collections;
namespace KNF
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
public static string[] Expressions = new string[]
{
"A*B+C",
"A+B*C",
"A+B*C+D",
"A*B+C*D",
"(A)",
"A*(B+C)",
"(A+B)*C",
"A",
"^A",
"^A+B",
"^(A+B)",
"A+^B*^C",
"A+B+C+D",
"(A+B)*(^A+B)",
"(A*B)+(^A*B)",
"(A+B)*(^A+B)*(A+^B)"
};
public static string[] Process(string[] expressions)
{
ArrayList results = new ArrayList;
foreach (string ex in expressions)
{
string expression = ex.Trim;
if (expression == "")
continue;
try
{
Expression expr = Parse(expression);
//OutputTree(expr);
Output(expr);
Expression notExpr = new NotExpression(expr);
Expression knfExpr = Knf(notExpr);
//OutputTree(knfExpr);
Expression mulExpr = BinToMultiply(knfExpr);
Expression simExpr = Simplify(mulExpr);
Output(knfExpr);
//OutputTree(knfExpr);
//OutputTree(mulExpr);
Output(simExpr);
Console.WriteLine;
bool isKnf = IsKnf(BinToMultiply(expr;

results.Add(string.Format("{2}!({0}) = {1}", expr, simExpr,
isKnf? " ":"[не кнф] ";
}
catch (Exception exc)
{
results.Add(string.Format("Ошибка - {0}", exc.Message;
}
}
return (string[])results.ToArray(typeof(string;
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
MainForm form = new MainForm;
System.Windows.Forms.Application.Run(form);

//string expression = "!A&B";
}
static bool IsKnf(Expression expr)
{
if (expr is MultiplyExpression)
{
MultiplyExpression mul = (MultiplyExpression)expr;
if (mul.Operation == Operation.And)
{
bool isKnf = true;
foreach (Expression childExpr in mul.Expressions)
{
if (!IsElementaryDnf(childExpr
isKnf = false;
}
return isKnf;
}
}
return IsElementaryDnf(expr);
}
static bool IsElementaryDnf(Expression expr)
{
if (expr is MultiplyExpression)
{
MultiplyExpression mul = (MultiplyExpression)expr;
if (mul.Operation == Operation.Or)
{
bool isDnf = true;
foreach (Expression childExpr in mul.Expressions)
{
if (!IsSimply(childExpr
isDnf = false;
}
return isDnf;
}
}
return IsSimply(expr);
}
static bool IsSimply(Expression expr)
{
if (expr is NotExpression)
{
NotExpression not = (NotExpression)expr;
return IsVariable(not.Expression);
}
return IsVariable(expr);
}
static bool IsVariable(Expression expr)
{
return expr is VariableExpression;
}
static Expression Simplify(Expression expr)
{
if (expr is MultiplyExpression)
{
MultiplyExpression mulExpr = (MultiplyExpression)expr;
if (mulExpr.Operation == Operation.Or)
{
Hashtable posIndex = new Hashtable;
Hashtable negIndex = new Hashtable;
ArrayList other= new ArrayList;
foreach (Expression ex in mulExpr.Expressions)
{
if (ex is VariableExpression)
{
posIndex[VariableExpression)ex).Variable] = ex;
}
else if (ex is NotExpression && NotExpression)ex).Expression is VariableExpression)
{
negIndex[VariableExpressionNotExpression)ex).Expression).Variable] = ex;
}
else
other.Add(ex);
}
ArrayList result = new ArrayList;
foreach (DictionaryEntry entry in posIndex)
{
if (negIndex.ContainsKey(entry.Key
return new VariableExpression("T");
result.Add(entry.Value);
}
result.AddRange(negIndex.Values);
result.AddRange(other);
return new MultiplyExpression(mulExpr.Operation,
(Expression[])result.ToArray(typeof(Expression;
}
if (mulExpr.Operation == Operation.And)
{
//ArrayList expressions = new ArrayList;
Hashtable exprIndex = new Hashtable;
foreach (Expression childEx in mulExpr.Expressions)
{
Expression ex = Simplify(childEx);
if (ex is VariableExpression && VariableExpression)ex).Variable == "T")
continue;
exprIndex[ex.ToString] = ex;
}
if (exprIndex.Count == 0)
return new VariableExpression("T");
return new MultiplyExpression(Operation.And,
(Expression[])new ArrayList(exprIndex.Values).ToArray(typeof(Expression;
}
ArrayList exprs = new ArrayList;
foreach (Expression ex in mulExpr.Expressions)
exprs.Add(Simplify(ex;
return new MultiplyExpression(mulExpr.Operation, (Expression[])exprs.ToArray(typeof(Expression;
}
return expr;
}
// static string Simplify_GetLexem(Expression expr)
// {
// if (expr is NotExpression)
// return Simplify_GetLexemNotExpression)expr).Expression);
// if (expr is VariableExpression)
// return VariableExpression)expr).Variable;
// return null;
// }
static Expression BinToMultiply(Expression expr)
{
if (expr is NotExpression)
return new NotExpression(BinToMultiplyNotExpression)expr).Expression;
if (expr is BinaryExpression)
{
BinaryExpression binExpr = (BinaryExpression)expr;
ArrayList exprs = new ArrayList;
foreach (Expression childExpr in BinToMultiply_Accumulate(binExpr.Operation, binExpr
exprs.Add(BinToMultiply(childExpr;
return new MultiplyExpression(binExpr.Operation,
(Expression[])exprs.ToArray(typeof(Expression;
}
return expr;
}
static ICollection BinToMultiply_Accumulate(string operation, Expression expr)
{
if (expr is BinaryExpression)
{
BinaryExpression binExpr = (BinaryExpression)expr;
if (binExpr.Operation == operation)
{
ArrayList expressions = new ArrayList;
expressions.AddRange(BinToMultiply_Accumulate(operation, binExpr.Left;
expressions.AddRange(BinToMultiply_Accumulate(operation, binExpr.Right;
return expressions;

bleyman

> Скажи, почему ты программируешь не на естественном языке?
потому что компьютер тупой и не понимает естественный язык.
Ыыыы. Никто не понимает естественный язык, к сожалению.

stm8823636

Лисп простой язык, никаких вопросов. Лисп хорошо читаем. Но ЛИСПОВИКИ- полные долбаебы. С вами невозможно нормально общаться.

myrka68

ох....еть!
охрененно просто и понятно...
мой моск умер...

Ivan8209

>> Скажи, почему ты программируешь не на естественном языке?
> потому что компьютер тупой и не понимает естественный язык.
Как из этого следует потребность изобретения языка с сильно неоднородным, как у сей, синтаксисом?
---
...Я работаю антинаучным аферистом...

bleyman

ох....еть!
охрененно просто и понятно...
мой моск умер...
А чего ты хочешь? Тут же задачи принципиально разные получаются: в лиспе строкоразбиратель встроенный, то есть преобразуемую ДНФ можно писАть без кавычек.
Даркгрей запостил код синтаксического анализатора, который переводит строчку в дерево, потом по-бырому преобразует дерево, потом выводит дерево обратно.

Dasar

> Через полчаса будет.
я правильно понимаю, что правильного решение до сих пор нет?

kokoc88

где подпрограмма, к которой на входе одна форма, а на выходе - она же после преобразования?
Поищи, она там есть.

Ivan8209


    public static string[] Process(string[] expressions)
    {
     ArrayList results = new ArrayList;
     foreach (string ex in expressions)
     {
     string expression = ex.Trim;
     if (expression == "")
     continue;
     try
     {
     Expression expr = Parse(expression);
     Output(expr);
     Expression notExpr = new NotExpression(expr);
     Expression knfExpr = Knf(notExpr);
     Expression mulExpr = BinToMultiply(knfExpr);
     Expression simExpr = Simplify(mulExpr);
     Output(knfExpr);
     Output(simExpr);
     Console.WriteLine;
     bool isKnf = IsKnf(BinToMultiply(expr;
     results.Add(string.Format("{2}!({0}) = {1}", expr, simExpr,
     isKnf? " ":"[не кнф] ";
     }
     catch (Exception exc)
     {
     results.Add(string.Format("Ошибка - {0}", exc.Message;
     }
     }
     return (string[])results.ToArray(typeof(string;
    }

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

     ArrayList results = new ArrayList;

сильно избыточны, а потому создают впечатление,
что ты программируешь на ассемблере.
---
...Я работаю антинаучным аферистом...

Marinavo_0507

> так устроит?
но это же пиздец!

Ivan8209

Заказчик удовлетворён, следовательно решение есть.
---
...Я работаю антинаучным аферистом...

Dasar

> охрененно просто и понятно...
никто не говорил, что будет просто и понятно - это я просто на просьбу -а показать понятные отдельные функции.
кстати, запощенный код решает более общую задачу, чем стоит в треде -
запощенный код - произвольное выражение приводит к упрощенной КНФ

Ivan8209

> в лиспе строкоразбиратель встроенный,
> то есть преобразуемую ДНФ можно писАть без кавычек.
Не вопрос, могу перевести на SML, там нет "встроенного строкоразбирателя."
---
...Я работаю антинаучным аферистом...

kokoc88

А теперь подумай, что лучше отражает действительность
"(define result (simplified conj-form" или твоё "ParseStringAndStoreToResultSimplified".
Действительность - первое, процесс получения действительности - второе. Большинство людей мыслят сначала процесс, потом результат. И пишут 1 + 1 = 2, а не = 2 (+ 1 1). А вообще давай ка вернёмся в конструктив. Где твои исправления для сортировки внутри ДФов, чтобы (a b c) и (b c a) считались одинаковыми?

bleyman

В первом же определении ты в три раза перекрыл пределы по читаемости.
Слабоватая модульность.
ыыы. А зачем ты к сишарповому коду применяешь какие-то свои пределы по читаемости?
Из логических элементов там один цикл, линейная последовательность действий и обработчик ошибок. Разбивать это дальше довольно глупо, ИМХО.
При наличии подсветки, нормальных отступов и пустых строк этод метод читается со скоростью чуть меньшей чем для естественного текста.

kokoc88

В первом же определении ты в три раза перекрыл пределы по читаемости.
Да? А вот для меня пределы читаемости вполне перекрывает наличие более трёх закрывающих скобок на одной строке.

Marinavo_0507

> понятные отдельные функции
функция Simplify, как-то не очень отдельная и понятная (там прямо внутри - какие-то хеш-таблицы сразу возникают, списки массивов и прочие сложности и очень длинная

Ivan8209

> Большинство людей мыслят сначала процесс, потом результат.
> И пишут 1 + 1 = 2
Где ты нашёл таких людей?
Давай выйдем на улицу и поспрашиваем, что такое, например, дуб.
Могу заранее объявить, что большинство людей скажут: "Дуб --- это [дерево такое]..."---
а не "вот такое-то и такое-то есть дуб."
---
"Расширь своё сознание!"

Marinavo_0507

> процесс получения действительности - второе
процесс - это сначала разбираем, потом упрощаем, потом куда-то сохраняем (а может, мы не хотим сохранять, а сразу на экран хотим!)
в примере контры парсера не было, так что его можно не учитывать, и я на него в других примерах не смотрел
а вот то, что нет выделенной функции упрощения, а вместо неё функция, которая делает всё - недостаток
странно, что ты не понимаешь этого, ты наверное с вмк?

Dasar

> функция Simplify, как-то не очень отдельная и понятная (там прямо внутри - какие-то хеш-таблицы сразу возникают, списки массивов и прочие сложности и очень длинная
а как ты без словарей собрался упрощать вот такое выражение:
AB + A^B
?

Marinavo_0507

ну не прямо же внутри главной функции их обходить
абстракция данных в примере такой сложности уже не помешает

Ivan8209

> А зачем ты к сишарповому коду применяешь какие-то свои пределы по читаемости?
Пределы не мои, а общие.
И относятся они не только к коду.
> Из логических элементов там один цикл, линейная
> последовательность действий и обработчик ошибок.
Из логических элементов достаточно композиции функций.
> При наличии подсветки, нормальных отступов и пустых строк
> этод метод читается со скоростью чуть меньшей чем для естественного текста.
"Читаемость" не сводится к тому, насколько просто читать,
но вашему восприятию это, судя по всему, недоступно.
Читаемость --- это когда можно легко прочитать и воспринять _всё_.
И про подсветку не надо, потому что текст _с_цветом_ ---
это уже совершенно другой текст.
Смотри, например, colorForth Чарльза Мура.
---
...Я работаю антинаучным аферистом...

Dasar

> Заказчик удовлетворён, следовательно решение есть.
т.е. правильность кода ты определяешь именно по этому условию?

Ivan8209

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

bastii

Определение ParseString перекрывает пределы читаемости, по меньшей мере, в два раза.
То же --- с main.
В общем, насильники ещё раз показали, как они понимают читаемость.
КОНТРА, ты вообще что программируешь. Из личного опыта, думаю многие со мной согласятся, для читабельности лучше пусть метод в один экран не влазит, и местами код повторяется, чем у тебя будет куча небольших методов и большая вложенность вызовов.

bleyman

Из личного опыта, думаю многие со мной согласятся, для читабельности лучше пусть метод в один экран не влазит, и местами код повторяется, чем у тебя будет куча небольших методов и большая вложенность вызовов.
Гы, я не соглашусь.
Потому что читаемость - вещь субъективная. То, что есть миллион сишников, которые согласны с тобой, никак не влияет на существование миллиона лисповиков, которые согласны с Контрой. При этом ваш спор выглядит как спор двух идиотов.

bleyman

В своем посте ты в три раза перекрыл пределы по читаемости.
Слабоватая модульность.
Код должен быть короткий, вот такой: perl -e '$?s:;s:s;;$?::s;;=]=>%-{<-|}<&|`{;;y; -/:-@[-`{-};`-{/" -;;s;;$_;see'
Коротко и понятно.

Papazyan

КОНТРА, ты вообще что программируешь. Из личного опыта, думаю многие со мной согласятся, для читабельности лучше пусть метод в один экран не влазит, и местами код повторяется, чем у тебя будет куча небольших методов и большая вложенность вызовов.
Это обскурантистский взгляд на программирование, истоки которого лежат в повальном использовании императивных языков низкого уровня в прошлом. Сейчас без разницы размер функций, компилятор лучше знает, как их заинлайнить.

bastii

Я не о компиляторе забочусь. Просто напрягает помнить, что делает каждая из этих вспомогательных функций. Даже продвинутые среды программирования, когда можно легко перейти к коду функции и вернуться обратно, не особо помогают.
То Fj: Да, видимо, недоразвитые мозги, плохо, что на Лиспе не прогаю. Правда, в шахматы без доски играть я тоже не умею.

Ivan8209

> Просто напрягает помнить, что делает каждая из этих вспомогательных функций.
Имена пробовал давать описательные, а не абы как?
У меня "load" и "load-pref[erence]s" обычно занимаются разным делом,
несмотря на то, что лезут смотреть в одно и то же место.
---
...Я работаю антинаучным аферистом...

Ivan8209

> Коротко и понятно.
Здесь предел перекрывается примерно в 5 раз.
В курсе, что "знак" и "знак алфавита" --- это две большие разницы?
---
"Расширь своё сознание!"

evgen5555

Хоть бы байтов парочку поменял, что ли

bastii

У меня "load" и "load-pref[erence]s" обычно занимаются разным делом,
несмотря на то, что лезут смотреть в одно и то же место.
Очень описательно. А что будешь делать если отдельный модуль в твоей проге будет несколько больше, чем сабж этого треда?

Ivan8209

Разделю его на части.
---
...Я работаю антинаучным аферистом...

bleyman

В этой строке всего 69 символов, среди которых 24 уникальных. Для сравнения - в сроке "В этой строке всего 69 символов, среди которых 24 уникальных." 61 и 28 соответственно.
Расскажи мне пожалуйста, что такое знак, что такое знак алфавита, и как ты оцениваешь читабельность.

bleyman

Хоть бы байтов парочку поменял, что ли
А это оно? Я просто был совершенно не уверен =)

Ivan8209

Насчёт читаемости ссылка уже давно приведена,
кстати, кто-то из вас двоих, тебя и Braindead-а, её и спрашивал.
Соответственно --- оценка читаемости.
---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."
Оставить комментарий
Имя или ник:
Комментарий: