[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Стабильная система?



Artem Chuprina <ran@lasgalen.net> writes:

> Dmitrii Kashin -> debian-russian@lists.debian.org  @ Wed, 07 Oct 2015 02:07:07 +0300:
>
>  DK> За время работы с ним меня приятно удивило после Haskell:
>
>  DK> 1) Позволяет более просто комбинировать функциональное и императивное
>  DK> программирование: не надо изворачиваться монадами, чтобы добиться
>  DK> последовательного выполнения команд.
>
> ...
>
> а зачем, собственно, добиваться последовательного выполнения никак не
> связанных между собой команд?

Я думаю, тут есть недоразумение. Требование последовательного выполнения
определённых команд как раз и определяет связь между ними. Если конечно
не считать, что связь -- это "результат А нужен для вычисления B". Тут
важно понять, что императивное программирование -- это именно
программирование с изменением состояния системы.

Зачем это нужно? Ну, бывают разные случаи.

Бывает, что это повышает производительность. В случае большого словаря
создание его дубликата при изменении значения одного ключа создаёт очень
большие накладные расходы.

Бывает, что это упрощает описание алгоритма. Например, если Вы
реализуете программу, алгоритм которой описан в императивном стиле в
некоторой статье, то логично пользоваться тем же представлением, что и
автор.

Бывает, что без этого обойтись невозможно. Такое случается, когда Ваша
программа должна некоторым образом взаимодействовать со внешней
средой. Вот пишете Вы, допустим, сборочную систему, и Вам принципиально
важно, чтобы были выполнены последовательно сначала git clone, а потом
git checkout.

>  DK> 2) Позволяет таки определять полиморфные функции. Да, это нарушение
>  DK> системы типов, но если этим не злоупотреблять, то это даже удобно.
>
> Какого именно вида полиморфных функций?  В хаскеле их минимум два (а с
> generics, пожалуй, и все три).

Прошу прощения, ошибся. Я уже начал подзабывать Haskell. Да, в Haskell
есть полиморфные функции.

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

Мне вот достался в наследство проект, который в виду крайне сумбурного
развития имеет ужасную архитектуру, и работает с горем
пополам. Благодаря возможности описания опциональных аргументов у
функций, я могу дополнять их функционалом, не меняя при этом их
поведения в старом коде.

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

let funA ?a ?(b=1) c = match a with
  | None -> b*c;
  | Some a -> a+b*c

И после этого каррировать её вот так:\

let funB = funA ~a:None ~b:2

При этом "funB 1" будет эквивалентна "funA ~b:2 1"

Вот тут ещё можно посмотреть очень интересное мнение:
http://blog.ezyang.com/2010/10/ocaml-for-haskellers/

>  DK> Я в своё время с Вашей подачи пытался взять Haskell наскоком. Увы, он
>  DK> меня расстроил по целому ряду причин. Если хотите, могу рассказать.
>
> Было бы интересно.  Я его и сам осваивал небыстро, и кое-что открываю в
> нем до сих пор, пятый год уже.  (Кое-что из этого, впрочем, и
> появилось-то в этом году.)

Если Вы не возражаете, я сегодня на работе сделал некоторую заготовку
для ответа Вам, но адаптировать её и выверять у меня уже нет сил. Потому
помещаю как есть.

********

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

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

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

Я уверен, что Haskell -- язык хороший, но в основном для алгоритмов, в
которых Вы заранее можете быть уверены: либо достаточно простых (простых
не значит коротких), либо строго доказанных математически.

Промучившись с этим делом полгода, я отошёл от этой задачи в сторону
Common Lisp'а, который хотя и динамически типизирован, сэкономил мне
кучу времени макросами и приличным FFI-ем (как подружить с которым
Haskell я понятья не имею, ибо опять же, ленивость).

Сейчас я работаю в основном на Racket Scheme, Emacs/Common Lisps и
Ocaml. Последний выглядит для меня примерно как Haskell, только без
ленивости. Синтаксис выразительный, но логика вычислений проще поддаётся
осмыслению, и дебаг также не вызывает трудностей.

> Я Вам открою, наверное, страшную тайну: в хаскеле вообще невозможно
> добиться последовательного выполнения команд, кроме как через
> зависимость "результат A нужен для вычисления B".  В монадах на сей
> предмет нет ничего волшебного.  Даже в монаде IO.  Я когда-то, посмотрев
> на ее реализацию и осознав, что она такое, ухитрился даже нарисовать
> тест, который это демонстрировал.

Ну, вот видите. Принудительная ленивость по умолчанию порождает ряд
очень не очевидных проблем, а плюсов её навязывания я не ощущаю.

Я не утверждаю, что они не решаемы. Возможно, я просто не смог до конца
разобраться. Но рекомендованного Вами "Learn Haskell for Great Good" мне
лично не хватило, чтобы уверенно работать.

Attachment: signature.asc
Description: PGP signature


Reply to: