0 / 0 / 0
Регистрация: 28.09.2013
Сообщений: 5
1

Декларативность в Haskell

28.09.2013, 20:15. Показов 2000. Ответов 15
Метки нет (Все метки)

Я новичок в Haskell и хочу спросить про декларативность. Не очень понимаю определение данного термина, сказано, что при декларативном программировании мы говорим проге "что" мы от него хотим и не задаемся вопросом "как" мы это реализуем, за это отвечает компилятор (интерпретатор). Если мы говорим о функциональном языке, то принято автоматически относить его к декларативным языкам. Но малость поизучав haskell пришел к выводу, что код haskell ничем практически не отличается от императивного кода (только с pattern matching и рекурсией), даже java с xml или ruby c dsl выглядят декларативнее, так что я не вижу особой разницы. Может я что-то не понимаю (пока дошел до монад).
__________________
Помощь в написании контрольных, курсовых и дипломных работ здесь
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
28.09.2013, 20:15
Ответы с готовыми решениями:

Место ФП и Haskell в компьютерной индустрии (Для чего он нужен, этот Haskell?)
"У нас" ? А где преподавание этой экзотики на высоте? Добавлено через 2 минуты А где такие...

HASKELL
Добрый вечер, прошу помощи у знающих Haskell, не понимаю его, не для меня видимо, но сдать...

Haskell
Ищу хаскелиста. Работа над серверной частью ERP системы. Кто заинтересовался писать на почту...

Рекурсия в Haskell
Помогите пожалуйста , начал осваивать функциональное программирование, но не совсем понимаю как...

15
144 / 134 / 8
Регистрация: 19.07.2011
Сообщений: 184
28.09.2013, 22:23 2
Цитата Сообщение от klondaiker Посмотреть сообщение
малость поизучав haskell пришел к выводу, что код haskell ничем практически не отличается от императивного кода (только с pattern matching и рекурсией), даже java с xml или ruby c dsl выглядят декларативнее
XML — декларативный язык. И DSL на Руби тоже может быть декларативным.
На том же C# библиотека LINQ — декларативная.

Но на Хаскеле вы никогда не пишете как что-то получить, именно только определения.

sum — это не «сложить все элементы списка», а «сумма элементов списка». Определена она как foldr (+) 0 — но это не «последовательно прибавлять элементы списка к накопительому параметру, изначально равному ноль», это «свертка списка сложением с начальным значением ноль». Разницу чувствуете? Вы нигде ни одного действия не описали.
1
Модератор
Эксперт функциональных языков программированияЭксперт Python
30647 / 16874 / 3476
Регистрация: 12.02.2012
Сообщений: 28,285
Записей в блоге: 5
29.09.2013, 12:01 3
Цитата Сообщение от klondaiker Посмотреть сообщение
haskell ничем практически не отличается от императивного кода
- вот тут самое время и привести два фрагмента кода: на Haskell и на C (к примеру). И указать черты явного сходства...

Добавлено через 19 минут
Задача: суммирование элементов списка/массива:

Код Haskell

Haskell
1
2
3
sumArr :: [Int] -> Int
sumArr []     = 0
sumArr (e:es) = e + sumArr es
Код C:

C
1
2
3
4
5
6
7
int sumArr(int *e, int i, int n)
{
    if (i == n) 
        return e[i];
    else
        return e[i]+sumArr(e,i+1,n);
}
Черты сходства, конечно, есть... Но нельзя отрицать явную императивность кода C и явную декларативность кода Haskell.
На мой взгляд, декларативность - понятие нестрогое.
Точное определение дать будет затруднительно. Но приведенный пример достаточно красноречив.
0
0 / 0 / 0
Регистрация: 28.09.2013
Сообщений: 5
29.09.2013, 15:46  [ТС] 4
Цитата Сообщение от Catstail Посмотреть сообщение
Черты сходства, конечно, есть... Но нельзя отрицать явную императивность кода C и явную декларативность кода Haskell.
Ну здесь наверно отличие Haskell от C заключается в pattern matching . Интересно, а в императивные языки, чисто в теории, возможно ли включить в синтаксис языка сопоставление по образцу? (анонимные функции же включили)
0
Модератор
Эксперт функциональных языков программированияЭксперт Python
30647 / 16874 / 3476
Регистрация: 12.02.2012
Сообщений: 28,285
Записей в блоге: 5
29.09.2013, 16:14 5
Цитата Сообщение от klondaiker Посмотреть сообщение
Ну здесь наверно отличие Haskell от C заключается в pattern matching
- не хотел бы начинать утомительный спор, сопоставление с образцом, на мой взгляд, не самая главная характеристика деклалативности... Вот Лисп-код этого же алгоритма:

Lisp
1
2
3
(defun aumArr (lst)
  (cond ((null lst) 0)
          (t (+ (car lst) (sumArr (cdr lst))))))
Сопоставления с образцом нет, а декларативность чувствуется.
0
14 / 9 / 2
Регистрация: 02.06.2013
Сообщений: 12
30.09.2013, 01:06 6
Приведённый код на Си мне видится вполне декларативным, единственная проблема - императивный return. Собственно, на Си можно писать в функциональном (декларативном) стиле, в большей мере это позволяет Си++ за счёт обобщённых алгоритмов (шаблонов). Также, на хаскелле можно писать код, подобный императивному (Lens). Я хочу сказать, что императивность кода зависит, в основном, от программиста и лишь во вторую очередь от языка. Хотя, безусловно, на функционально-ориентированных языках писать декларативно проще, чем на императивно-ориентированных.
1
111 / 85 / 21
Регистрация: 06.06.2011
Сообщений: 411
Записей в блоге: 1
30.09.2013, 13:50 7
императивный стиль - КАК сделать.
декларативный - ЧТО сделать.
1
163 / 163 / 22
Регистрация: 23.02.2011
Сообщений: 347
30.09.2013, 16:29 8
klondaiker,
вот типичный код на хаскеле
Haskell
1
2
3
4
5
6
7
someFunc = f1 (a + b) `op1` c
  where
   f1 = ...
   a = ...
   b = ..
   c = ...
   op1 = ...
Ты не задаешь порядок выражений продекларированных в where. Несмотря на то, что С объявлена позже В, С может быть вычислена раньше В, а може и позже В. А еще они могут быть взаимно рекурсивными. Ты не задаешь порядок вычисления этих переменных, лишь указываешь, какие значения тебе нужны для вычисления целевой функции. Это и есть декларативность. Ни в java, ни в ruby такоге нет.
2
Модератор
Эксперт функциональных языков программированияЭксперт Python
30647 / 16874 / 3476
Регистрация: 12.02.2012
Сообщений: 28,285
Записей в блоге: 5
30.09.2013, 18:02 9
Цитата Сообщение от Algiz Посмотреть сообщение
Ни в java, ни в ruby такоге нет.
- да, вот точное замечание!
0
Эксперт по математике/физике
4156 / 2059 / 424
Регистрация: 19.07.2009
Сообщений: 3,117
Записей в блоге: 24
30.09.2013, 19:24 10
Лучший ответ Сообщение было отмечено как решение

Решение

Может, я поступлю не очень мудро, но я встану на сторону ТС.

Сtrl описал характерную черту декларативного стила и привёл пример. Поблагодарите его, написано хорошо.

Пример, который привёл Catstail в сообщении #3 действительно можно трактовать неоднозначно. Вроде как декларативная подоснова рекуррентного суммирования (хотя коды-то не полностью эквивалентны: число аргументов разное, но это можно проигнорировать, потому что два доп. аргумента нужны для того, чтоб исключить неудобство из-за отсутствия pattern matching; другой вариант решения — ввести явно функции head и tail в обоих языках, тогда код вообще будет похож) одинакова в обоих случаях, да и
C
1
2
3
4
    if (i == n) 
        return e[i];
    else
        return e[i]+sumArr(e,i+1,n);
вроде как можно переписать в виде
C
1
return (i==n) ? e[i] : e[i] + sumArr(e,i+1,n)
и не всем не до конца может быть понятно, на что именно акцентирует внимание Catstail

Дело же в том, что стиль программирования определяется вовсе не языком, а программистом. Язык же только предоставляет необходимый инструмент для использования некоторых стилей. Например, Java является ООЯП, т.е. предоставляет инструменты для ООП, а Haskell — ФЯП, т.е. для функциональщины. В теме Стоит ли использовать ООП? поднимался вопрос о том, можно ли считать программирование на Java объектно-ориентированным, если весь код помещён под знамёна static модификатора. Я склоняюсь к тому, что программирование в static ничем не отличается от программирования на C/Pascal.
Следовательно, язык не определяет стиль.
Смысл декларативного стиля был дан и согласно нему можно писать некий код на любом ЯП. Например, если Вы каким-то образом определите функции foldr и (+), то сумматор можно определить вполне в декларативном стиле:
Haskell
1
sum = foldr (+) 0
C
1
2
3
4
5
6
7
8
// не знаю C, поэтому код схематичен
int plus(int a, int b) { return a+b; }
void * foldr(void * op, int z) {
    // op callback
    // возвращает тоже колбек
    // ...
}
void * sum = foldr(plus, 0);
Корректный вариант на Java
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Main {
 
    interface Map<A,B> { B map(A x); }
    interface Binary<A> { A map(A x, A y); }
 
    static class Plus implements Binary<Integer> {
        public Integer map(Integer x, Integer y) {
            return x + y;
        }
    }
    static class Fold<A> implements Map<Binary<A>,Map<A, Map<List<A>,A>>> {
        public Map<A, Map<List<A>,A>> map(final Binary<A> op) {
            return new Map<A, Map<List<A>,A>>() {
                public Map<List<A>,A> map(final A z) {
                    return new Map<List<A>,A>() {
                        public A map(List<A> list) {
                            // здесь доступны op, z, list
                            // например, так напишем
                            A y = z;
                            for(A x : list)
                                y = op.map(y,x);
                            return y;
                        }
                    };
                }
            };
        }
    }
    // следующая строчка вполне себе декларативная!
    static final Map<List<Integer>, Integer> sum = new Fold<Integer>().map(new Plus()).map(0);
}
Вот, собственно, я повторил мысль netrino.

Здесь, однако, Algiz вбросил аргумент, мимо которого спокойно пройти нельзя: Хаскелль придерживается ленивой стратегии редукции, в то время как императивные языка — активной, и это даёт возможность писать некоторые вещи, как перекрёстное определение, самопосылка и введение невостребованных символов, которые редуцировать нельзя или проблематично, а потому критичен порядок редукции.
Решается эта проблема таким наблюдением: всякий тип x эквивалентен типу 1 -> x, где 1 — это void, () или любой другой тип с принципиально единственно возможным вычислимым значением. В ООП это используется повсеместно и называется геттером. Действительно, если у нас есть некий объект a, то можем составить функцию \ _ -> a, и наоборот, всякому getter можно сопоставить getter(). Если a из себя представляет конкретное значение, то всё очевидно. Если a — выражение, то относительно ленивой стратегии ничего не поменялось, зато относительно активной мы получили возможность контролировать порядок выполнения, потому что getter не начнёт редуцироваться до момента, когда он будет вызван. Кстати, вопрос с кешированием тоже можно разрешить чисто языковыми средствами. Другими словами, всякий вопрос, который возлагается на GHC или какой ещё компилятор, можно решить средствами языка в C/..., притом значимый код будет соответствовать такому же по структуре, а значит и по стилю.
Контраргумент «вот мы пишем определение объекта и манипулируем с ним как с объектом, а не с функцией, в этих ваших C/Java/... нужно обязательно функции делать» не принимается по той причине, что здесь существенную роль играет компилятор. С таким же успехом можно сказать: на С никогда нельзя писать также, как на Java (даже если всё под static — всё написанно в традициях обычного императивного программирования без чего-либо ещё особенного, вроде ООП), потому что в Java есть автоматическая сборка мусора, а в С такой нет. Вопрос одиного характера: язык не предполагает контроль за неким ресурсом (порядок редукции / память), а потому компилятор вынужден наиболее оптимальным образом контролировать расход этого ресурса (выбирать порядок редукции / освобождать память)

Спасибо за внимание )

upd. я, возможно, несколько вольно и неточно обращаюсь с такими понятиями как «стиль», «декларативный», «императивный», «функциональный», «ОО» и пр.
Подробнее о специфике можно почитать в статье Peter Van Roy Programming Paradigms for Dummies: What Every Programmer Should Know.
Я её ещё не осилил (
5
Модератор
Эксперт функциональных языков программированияЭксперт Python
30647 / 16874 / 3476
Регистрация: 12.02.2012
Сообщений: 28,285
Записей в блоге: 5
30.09.2013, 19:28 11
Цитата Сообщение от Mysterious Light Посмотреть сообщение
Дело же в том, что стиль программирования определяется вовсе не языком, а программистом.
+100!
0
0 / 0 / 0
Регистрация: 28.09.2013
Сообщений: 5
01.10.2013, 01:34  [ТС] 12
Цитата Сообщение от Mysterious Light Посмотреть сообщение
Смысл декларативного стиля был дан и согласно нему можно писать некий код на любом ЯП.
Да, можно исхитриться написать свои какие-то самописные костыли (как в вашем примере с C и Java) и постоянно их использовать в коде, но без дефолтной поддержки декларативного стиля со стороны языка (синтаксиса и тд) прогать в этом стиле будет наверно тяжело.

Если по теме, то кажется я врубаюсь потихоньку в чем дело. Спасибо всем кто ответил.
0
Эксперт по математике/физике
4156 / 2059 / 424
Регистрация: 19.07.2009
Сообщений: 3,117
Записей в блоге: 24
01.10.2013, 03:31 13
Цитата Сообщение от klondaiker Посмотреть сообщение
Да, можно исхитриться написать свои какие-то самописные костыли (как в вашем примере с C и Java) и постоянно их использовать в коде, но без дефолтной поддержки декларативного стиля со стороны языка (синтаксиса и тд) прогать в этом стиле будет наверно тяжело.
Ну да, потому и говорят, что программа написана в таком-то стиле, а язык предрасположен к такому-то стилю.

Для сравнения: JavaScript предрасположен к одному стилю, а CoffeeScript, который по сути является тем же JavaScript, только команды по-другому называются, а языковые конструкции ровно те же, предрасположен немножко к другому.
Вот ввели в C# лямбды и стал раем для полу-функциональщиков. Вот ввели в Java лямбды — то же самое.
А до тех пор пользуемся костылями или меняем стиль на более удобный.

Кстати, на Haskell решать задачи в императивном стиле тоже бывает сложно, но возможно.
0
2303 / 1062 / 77
Регистрация: 12.03.2013
Сообщений: 4,983
03.10.2013, 18:40 14
Цитата Сообщение от Mysterious Light Посмотреть сообщение
Дело же в том, что стиль программирования определяется вовсе не языком, а программистом.
Категорически не согласен с вами. Язык и community определяет правила и формирует мышление.
Цитата Сообщение от Mysterious Light Посмотреть сообщение
можно ли считать программирование на Java объектно-ориентированным, если весь код помещён под знамёна static модификатора
Это называется "в чужой монастырь со своими правилами" и, как в известной шутке, "программист на Fortran на любом языке напишет программу на Fortran"

Добавлено через 57 минут
Цитата Сообщение от Mysterious Light Посмотреть сообщение
Здесь, однако, Algiz вбросил аргумент, мимо которого спокойно пройти нельзя: Хаскелль придерживается ленивой стратегии редукции, в то время как императивные языка — активной
Далеко не все ФЯП-ы придерживаются ленивых вычислений и вообще модель вычислений не является особой характеристикой ФП. Посмотрите, например, на ML, OCaml, Erlang...

Добавлено через 1 минуту
Цитата Сообщение от Mysterious Light Посмотреть сообщение
а CoffeeScript, который по сути является тем же JavaScript, только команды по-другому называются, а языковые конструкции ровно те же
Вовсе нет. CoffeeScript, как не странно, весьма отличается от js. Например, в CoffeeScript все конструкции являются выражениями.
0
Эксперт Java
3882 / 2503 / 448
Регистрация: 28.04.2012
Сообщений: 8,201
03.10.2013, 18:57 15
Из SICP:
Миниатюры
Декларативность в Haskell  
2
25 / 25 / 2
Регистрация: 17.03.2013
Сообщений: 48
03.10.2013, 20:36 16
Цитата Сообщение от Сtrl Посмотреть сообщение
sum — это не «сложить все элементы списка», а «сумма элементов списка». Определена она как foldr (+) 0
Позвольте поправить неточность: foldr не такая быстрая, как foldl, а с учётом симметричности (+) --- результат тот же, поэтому лучше
Haskell
1
sum  =  foldl (+) 0
. В исходном коде так и есть.
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
03.10.2013, 20:36

Template Haskell
Как переписать этот код с помощью цитирующих скобок... заранее спасибо. fstN :: Int -&gt; Q Exp fstN...

Массивы в Haskell
У меня возникла такая проблемма. Нужно на Haskell, написать программу, которая находит нужный...

Clean vs Haskell
Интересует подробное сравнение чистых функциональных языков программирования семейства ML: Clean и...

Задачки по Haskell
Определить последовательность, в которой каждый элемент — список всех простых делителей...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru