Haskell язык программирования декларативный

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

Я новичок в Haskell и хочу спросить про декларативность. Не очень понимаю определение данного термина, сказано, что при декларативном программировании мы говорим проге «что» мы от него хотим и не задаемся вопросом «как» мы это реализуем, за это отвечает компилятор (интерпретатор). Если мы говорим о функциональном языке, то принято автоматически относить его к декларативным языкам. Но малость поизучав haskell пришел к выводу, что код haskell ничем практически не отличается от императивного кода (только с pattern matching и рекурсией), даже java с xml или ruby c dsl выглядят декларативнее, так что я не вижу особой разницы. Может я что-то не понимаю (пока дошел до монад).

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

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

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

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

ЦитатаСообщение от klondaiker Посмотреть сообщение

малость поизучав haskell пришел к выводу, что код haskell ничем практически не отличается от императивного кода (только с pattern matching и рекурсией), даже java с xml или ruby c dsl выглядят декларативнее

XML — декларативный язык. И DSL на Руби тоже может быть декларативным.
На том же C# библиотека LINQ — декларативная.

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

sum — это не «сложить все элементы списка», а «сумма элементов списка». Определена она как foldr (+) 0 — но это не «последовательно прибавлять элементы списка к накопительому параметру, изначально равному ноль», это «свертка списка сложением с начальным значением ноль». Разницу чувствуете? Вы нигде ни одного действия не описали.

Эксперт функциональных языков программированияЭксперт Python

ЦитатаСообщение от klondaiker Посмотреть сообщение

— вот тут самое время и привести два фрагмента кода: на Haskell и на C (к примеру). И указать черты явного сходства.

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

sumArr :: [Int] -> Int sumArr [] = 0 sumArr (e:es) = e + sumArr es
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.
На мой взгляд, декларативность — понятие нестрогое.
Точное определение дать будет затруднительно. Но приведенный пример достаточно красноречив.

ЦитатаСообщение от Catstail Посмотреть сообщение

Черты сходства, конечно, есть. Но нельзя отрицать явную императивность кода C и явную декларативность кода Haskell.

Ну здесь наверно отличие Haskell от C заключается в pattern matching . Интересно, а в императивные языки, чисто в теории, возможно ли включить в синтаксис языка сопоставление по образцу? (анонимные функции же включили)

Эксперт функциональных языков программированияЭксперт Python

ЦитатаСообщение от klondaiker Посмотреть сообщение

— не хотел бы начинать утомительный спор, сопоставление с образцом, на мой взгляд, не самая главная характеристика деклалативности. Вот Лисп-код этого же алгоритма:

(defun aumArr (lst) (cond ((null lst) 0) (t (+ (car lst) (sumArr (cdr lst))))))

Приведённый код на Си мне видится вполне декларативным, единственная проблема — императивный return. Собственно, на Си можно писать в функциональном (декларативном) стиле, в большей мере это позволяет Си++ за счёт обобщённых алгоритмов (шаблонов). Также, на хаскелле можно писать код, подобный императивному (Lens). Я хочу сказать, что императивность кода зависит, в основном, от программиста и лишь во вторую очередь от языка. Хотя, безусловно, на функционально-ориентированных языках писать декларативно проще, чем на императивно-ориентированных.

someFunc = f1 (a + b) `op1` c where f1 = . a = . b = .. c = . op1 = .

Ты не задаешь порядок выражений продекларированных в where. Несмотря на то, что С объявлена позже В, С может быть вычислена раньше В, а може и позже В. А еще они могут быть взаимно рекурсивными. Ты не задаешь порядок вычисления этих переменных, лишь указываешь, какие значения тебе нужны для вычисления целевой функции. Это и есть декларативность. Ни в java, ни в ruby такоге нет.

Эксперт функциональных языков программированияЭксперт Python

ЦитатаСообщение от Algiz Посмотреть сообщение

Эксперт по математике/физике

Лучший ответ

Сообщение было отмечено как решение

Решение

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

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

Пример, который привёл Catstail в сообщении #3 действительно можно трактовать неоднозначно. Вроде как декларативная подоснова рекуррентного суммирования (хотя коды-то не полностью эквивалентны: число аргументов разное, но это можно проигнорировать, потому что два доп. аргумента нужны для того, чтоб исключить неудобство из-за отсутствия pattern matching; другой вариант решения — ввести явно функции head и tail в обоих языках, тогда код вообще будет похож) одинакова в обоих случаях, да и

if (i == n) return e[i]; else return e[i]+sumArr(e,i+1,n);
return (i==n) ? e[i] : e[i] + sumArr(e,i+1,n)

и не всем не до конца может быть понятно, на что именно акцентирует внимание Catstail

Дело же в том, что стиль программирования определяется вовсе не языком, а программистом. Язык же только предоставляет необходимый инструмент для использования некоторых стилей. Например, Java является ООЯП, т.е. предоставляет инструменты для ООП, а Haskell — ФЯП, т.е. для функциональщины. В теме Стоит ли использовать ООП? поднимался вопрос о том, можно ли считать программирование на Java объектно-ориентированным, если весь код помещён под знамёна static модификатора. Я склоняюсь к тому, что программирование в static ничем не отличается от программирования на C/Pascal.
Следовательно, язык не определяет стиль.
Смысл декларативного стиля был дан и согласно нему можно писать некий код на любом ЯП. Например, если Вы каким-то образом определите функции foldr и (+), то сумматор можно определить вполне в декларативном стиле:

// не знаю C, поэтому код схематичен int plus(int a, int b) { return a+b; } void * foldr(void * op, int z) { // op callback // возвращает тоже колбек // . } void * sum = foldr(plus, 0);
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 MapA,B> { B map(A x); } interface BinaryA> { A map(A x, A y); } static class Plus implements BinaryInteger> { public Integer map(Integer x, Integer y) { return x + y; } } static class FoldA> implements MapBinaryA>,MapA, MapListA>,A>>> { public MapA, MapListA>,A>> map(final BinaryA> op) { return new MapA, MapListA>,A>>() { public MapListA>,A> map(final A z) { return new MapListA>,A>() { public A map(ListA> list) { // здесь доступны op, z, list // например, так напишем A y = z; for(A x : list) y = op.map(y,x); return y; } }; } }; } } // следующая строчка вполне себе декларативная! static final MapListInteger>, Integer> sum = new FoldInteger>().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.
Я её ещё не осилил (

Источник

Haskell

Haskell — функциональный декларативный язык программирования, первая версия которого была стандартизирована в 1990 году, назван в честь математика Хаскелла Карри. Язык Haskell известен благодаря синтаксису, в сравнении с которым пёрл выглядит псевдокодом, а также необходимостью глубокого понимания лямбда-исчисления, замыканий, теории графов, теории категорий, сопромата, анатомии мозга и прочего матана даже для вывода на экран строки «Hello, World!»

История

В 1958 году был изобретён первый функциональный язык программирования — Лисп. К 80-м годам прошлого века функциональных языков стало очень много. Каждый задрот считал своим долгом изобрести свой. И вот однажды, в 1987 году было решено создать язык, который бы включал лучшие достижения из всех языков программирования. Собрался специальный комитет из отборнейших задротов и без лишнего шума создали его. Предшественниками хаскеля были ML, SML, Miranda. Кроме того туда добавили немного лиспа, пролога, матана и ещё чего-то там. Что касается названия, то однажды во время пьянки задроты просто взяли и выбрали общим голосованием «хаскель» из 25 рандомных слов. Читай @ просвещайся.

Хаскель, чаны и все-все-все

Хаскель и лисп — популярные и постоянные мемы в /s/ и /prog/. Как это сочетается с большой популярностью хаскеля в очень узкой академической среде — не ясно.

Востребованность

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

Не будем забывать, что хаскель наиболее активно разрабатывается в недрах Microsoft Research. Nuff Said. Обыдленный хаске…^W ML под названием F# включен в Visual Studio 2010, а это значит, что скоро знание хаскеля будет как минимум преимуществом при поступлении на работу.

Примеры кода на Haskell

import Random;import List;import Char;p=putStrLn;u=uncurry;f x=(x\\).(x\\) main=mapM(\x->randomRIO(49,54))[1..4]>>=n 0.map chr>>=p.("Tries: "++).show e=((partition$u(==)).).zip;h(p,q)=['*'|xp]++['+'|x(u f)$unzip q] n a s=getLine>>=m wherem i|i==s=return a;m i=p(h$e i s)>>n(a+1)s> 
main :: IO () main = putStrLn "Hello, world!" 
  module Hello where import Language.BASIC main :: IO () main = runBASIC $ do 10 PRINT "Hello BASIC World!" 
fac n = if n == 1 then 1 else (fac n-1) * n 
fac 1 = 1 fac n = fac (n-1) * n 
s f g x = f x (g x) k x y = x b f g x = f (g x) c f g x = f x g y f = f (y f) cond p f g x = if p x then f x else g x fac = y (b (cond ((==) 0) (k 1)) (b (s (*)) (c b pred))) 

А это программа на Haskell, которая выводит программу на Python, которая выводит программу на Ruby, которая выводит исходную программу на Haskell.

q a b c=putStrLn $ b ++ [toEnum 10,'q','('] ++ show b ++ [','] ++ show c ++ [','] ++ show a ++ [')'] main=q "q a b c=putStrLn $ b ++ [toEnum 10,'q','('] ++ show b ++ [','] ++ show c ++ [','] ++ show a ++ [')']" "def q(a,b,c):print b+chr(10)+'q('+repr(b)+','+repr(c)+','+repr(a)+')'" "def e(x) return 34.chr+x+34.chr end;def q(a,b,c) print b+10.chr+'main=q '+e(b)+' '+e(c)+' '+e(a)+' '+10.chr end" 

Источник

Читайте также:  Программирование моделирования системы массового обслуживания
Оцените статью