Re[12]: Неправильное введение в функциональное программирование
От: AlexRK  
Дата: 29.11.13 15:34
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Дело в том, что boost::variant обеспечивают такую статическую проверку (выше я уже это упоминал).

EP>Например, если добавить новый продукт, но не изменив visitor, то будет ошибка компиляции:

А кроме визитора распаковать вариант никак нельзя? Что-нибудь вроде "if (x is Cellphone)"...
Re[13]: Неправильное введение в функциональное программирование
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 29.11.13 15:57
Оценка: +1
Здравствуйте, AlexRK, Вы писали:

ARK>А кроме визитора распаковать вариант никак нельзя? Что-нибудь вроде "if (x is Cellphone)"...


Справедливости ради, в нетотальных языках вроде хаскеля есть и функции вроде fromJust и tail, которые не заставляют обрабатывать все варианты, а предполагают один, а если там был другой, то происходит рантайм ошибка. Так что тут в некотором смысле паритет. Вот в языках с проверкой тотальности, типа того же идриса, уже построже проверки.
Re[13]: Неправильное введение в функциональное программирование
От: Evgeny.Panasyuk Россия  
Дата: 29.11.13 15:58
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>А кроме визитора распаковать вариант никак нельзя? Что-нибудь вроде "if (x is Cellphone)"...


Там есть x.which() который возвращает номер текущего типа, и есть x.type(), который возвращает std::type_info.
Плюс есть get<T>(x) — если в X находится объект типа T, то он возвращается, иначе кидается исключение, то есть сделать "внешний" switch/if можно.
Но тут два момента:
1. При необходимости, get можно запретить, сделав wrapper на boost::variant, или полностью свой.
2. Ручной if/switch по части возможных типов, означает что мы сознательно делаем для остальных "match all default", а-ля "_".
Re[14]: Неправильное введение в функциональное программирование
От: Evgeny.Panasyuk Россия  
Дата: 29.11.13 16:01
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Вот в языках с проверкой тотальности, типа того же идриса, уже построже проверки.


А есть ли там возможность сматчить только один тип, а для остальных выполнить default?
Re[14]: Неправильное введение в функциональное программирование
От: AlexRK  
Дата: 29.11.13 16:14
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Там есть x.which() который возвращает номер текущего типа, и есть x.type(), который возвращает std::type_info.

EP>Плюс есть get<T>(x) — если в X находится объект типа T, то он возвращается, иначе кидается исключение, то есть сделать "внешний" switch/if можно.
EP>Но тут два момента:
EP>1. При необходимости, get можно запретить, сделав wrapper на boost::variant, или полностью свой.
EP>2. Ручной if/switch по части возможных типов, означает что мы сознательно делаем для остальных "match all default", а-ля "_".

Понятно. Но как-то вот не покидает ощущение, что это все кривоватая эмуляция. Необходимость создания кучи визиторов (и прокидывать в каждый из них необходимый контекст!), и враппер для защиты. Можно ведь, аналогичным образом рассуждая, эмулировать константы в языке, их не имеющем, путем "соглашения не менять определенные переменные". Однако константы от этого в языке не появляются. В общем, на мой взгляд, не тянет это на "прекрасно реализуется".
Re[14]: Неправильное введение в функциональное программирование
От: AlexRK  
Дата: 29.11.13 16:16
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Справедливости ради, в нетотальных языках вроде хаскеля есть и функции вроде fromJust и tail, которые не заставляют обрабатывать все варианты, а предполагают один, а если там был другой, то происходит рантайм ошибка. Так что тут в некотором смысле паритет. Вот в языках с проверкой тотальности, типа того же идриса, уже построже проверки.


В таком случае наверное да, все аналогично. У С++ все хуже по части бойлерплейта.
Re[15]: Неправильное введение в функциональное программирование
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 29.11.13 16:28
Оценка: 7 (1)
Здравствуйте, Evgeny.Panasyuk, Вы писали:

DM>>Вот в языках с проверкой тотальности, типа того же идриса, уже построже проверки.

EP>А есть ли там возможность сматчить только один тип, а для остальных выполнить default?

Для конечных сумм (вроде Maybe, Either и т.п., где число вариантов фиксировано) можно: _. Даже если потом тип изменится, и в сумме появится новый вариант, функция с _ отработает без рантайм ошибок, что и требовалось.
С более хитрыми типами уже не уверен.
Re[15]: Неправильное введение в функциональное программирование
От: Evgeny.Panasyuk Россия  
Дата: 29.11.13 16:40
Оценка: 34 (1)
Здравствуйте, AlexRK, Вы писали:

ARK>Понятно. Но как-то вот не покидает ощущение, что это все кривоватая эмуляция. Необходимость создания кучи визиторов (и прокидывать в каждый из них необходимый контекст!)


Я показал C++1998 код.
В C++11/14 boilerplate при желании убирается:
v.visit
(
    [](Laptop &laptop) { cout << laptop.x; },
    [](Cellphone &phone) { cout << phone.y; },
    [](auto &any) { cout << any.something; }
);


ARK>и враппер для защиты.


Wrapper для защиты и не нужен (а если нужен — пишется один раз) — даже в тех языках где нет match-all-default, всегда можно его сделать вручную:
match_only_laptop(Variant x, Action f, Action default)
{
    match(Laptop) as laptop: f(laptop)
    match(Cellphone) as d : default(d)
    match(Desktop) as d : default(d)
}


ARK>Можно ведь, аналогичным образом рассуждая, эмулировать константы в языке, их не имеющем, путем "соглашения не менять определенные переменные". Однако константы от этого в языке не появляются. В общем, на мой взгляд, не тянет это на "прекрасно реализуется".


Константы дают возможность проверить компилятору некоторые инварианты статически.
boost::variant-like также позволяет проверить делать статические проверки — это не какое-то внешнее соглашение, а разговор на вполне понятном компилятору языке.
Re[16]: Неправильное введение в функциональное программирование
От: AlexRK  
Дата: 29.11.13 16:57
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Я показал C++1998 код.

EP>В C++11/14 boilerplate при желании убирается:

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

К примеру вот на псевдокоде:

  var foo: Integer := ...
  var bar: String := ...

  case variant

    when CellPhone then
      print("Phone count: ", foo + 3);

    when Laptop then
      print(bar, variant.x);

  end;


Мы же можем использовать при паттерн-матчинге и локальные переменные, и параметры метода, и поля класса. Все это добро придется передавать в визиторы.
Re[17]: Неправильное введение в функциональное программирование
От: Evgeny.Panasyuk Россия  
Дата: 29.11.13 17:04
Оценка: +1
Здравствуйте, AlexRK, Вы писали:

EP>>Я показал C++1998 код.

EP>>В C++11/14 boilerplate при желании убирается:

ARK>Да, так лучше. Но визиторов все равно придется писать много, в общем случае по одному на каждый вызов — контекст-то везде разный.


Так и matcher'ы будут на каждый вызов

ARK>К примеру вот на псевдокоде:

ARK>
ARK>  var foo: Integer := ...
ARK>  var bar: String := ...

ARK>  case variant

ARK>    when CellPhone then
ARK>      print("Phone count: ", foo + 3);

ARK>    when Laptop then
ARK>      print(bar, variant.x);

ARK>  end;
ARK>

ARK>Мы же можем использовать при паттерн-матчинге и локальные переменные, и параметры метода, и поля класса. Все это добро придется передавать в визиторы.

Тут нет проблемы, лямбды умеют захватывать контекст:
int foo;
string bar;
v.visit
(
    [&](Cellphone &phone) { cout << "Phone count: " << (foo + 3); },
    [&](Laptop &laptop) { cout << bar << laptop.x; }
);
Re[18]: Неправильное введение в функциональное программирование
От: AlexRK  
Дата: 29.11.13 17:12
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Тут нет проблемы, лямбды умеют захватывать контекст:


А! Понял. Не увидел сразу, что там вызов, а не объявление класса. Да, последний вариант, похоже, является полной аналогией с АТД.
Re[19]: Неправильное введение в функциональное программирование
От: Evgeny.Panasyuk Россия  
Дата: 29.11.13 17:17
Оценка:
Здравствуйте, AlexRK, Вы писали:

EP>>Тут нет проблемы, лямбды умеют захватывать контекст:

ARK>А! Понял. Не увидел сразу, что там вызов, а не объявление класса. Да, последний вариант, похоже, является полной аналогией с АТД.

Да. (не считая, как заметил D. Mon, pattern-matching'а — но он и не обсуждался в статье)
Re[20]: Неправильное введение в функциональное программирование
От: Воронков Василий Россия  
Дата: 29.11.13 18:18
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Просто у тебя один вид значений отличался от другого тэгом Some, а здесь для них заведены тэги Nbr и Fn, смысл тот же абсолютно.


Ну, правильно, ты поменял код и устранил зависимость от рантайм значений. И что ты хотел этим доказать? Понятно, что аналогичную программу можно написать на любом языке. Она приводилась в качестве примера реализации.
Re[20]: Неправильное введение в функциональное программирование
От: Воронков Василий Россия  
Дата: 29.11.13 18:27
Оценка: -1
Здравствуйте, D. Mon, Вы писали:

DM>Звучит как немерлизм, ни в одном нормальном языке такого нет (чтобы именно первого). Формально это ересь, тип функции тут указан уже при определении, а потом лишь используется. Но если речь просто про полиморфизм, то да, тут одна из его форм, параметризованный тип.


Никакой это не немерлизм. Это, может, в OCaml не так, где не потрудились ХМ допилить. А в языках с полиморфными операторами ты даже функцию "sum x y =x+y" иначе не типизируешь. Ибо какой у нее тип?

ВВ>>Здесь нет зависимости от рантайм значений, ведь эта программа доказывается статически. "Доказывается статически" означает, что возможный диапазон значений нам известен в компайл тайм, и мы можем доказать, что ни при каких случаях не выйдем из этого диапазона. Откуда здесь взяться зависимости от рантайма? Тут ее нет


DM>Ну что значит нет? Значение v тут один раз создается и передается. Какого оно типа? Зависит от того, как мы программу запустили, что ей передали. Это и есть зависимость от рантайма в чистом виде, а не твои странные определения.


Ну да.

x = 2


Это тоже рантайм значение. Вот только известно оно в компайл-тайме.
Повторяю — зависимость от рантайм-значений означает зависимость от значений, которые *известны* только в рантайме.

ВВ>>"Зависимость от рантайм-значений" означает "Зависимость от значений, который становятся *известны* только в рантайме".

DM>Ровно так и есть же в этом примере. Есть зависимость типа от булевого значения, истина там или ложь — будет известно только в рантайме.

Диапазон значений известен в компайл, соответственно, всё просчитывается статически.

BB>>А для того, чтобы программа была доказуема статически, ее нужно свести к набору значений, который известен уже в период компиляции. Никаких "нежданчиков" там быть не может. Так что это, мягко говоря, не одно и то же


DM>Да, "набор" значений должен быть известен статически, но он может быть бесконечным. В примере выше, где список читался извне, тип функции зависел от длины списка, который мог быть сколь угодно длинным (если закрыть глаза на технические ограничения ОС). Т.е. в зависимости от переданных данных могло получиться значение типа


Там была зависимость от длины списка. Для доказательства корректности достаточно было того, чтобы длина была длиной именно списка, что компилятор прекрасно видел в коде "length xs" и "fun xs".

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


Статическая типизация устраняет не баги, а все, что не может просчитать статически. Любую ситуацию с "нежданчиком" можно обработать — на основе данных, которые становятся доступны только в рантайме. Не говоря уж о том, что на практике любая система типов имеет свои ограничения и может не пропускать корректный код просто потому что не способна его доказать.
Re[21]: Неправильное введение в функциональное программирование
От: Klapaucius  
Дата: 29.11.13 18:55
Оценка: +1
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Никакой это не немерлизм. Это, может, в OCaml не так, где не потрудились ХМ допилить. А в языках с полиморфными операторами ты даже функцию "sum x y =x+y" иначе не типизируешь. Ибо какой у нее тип?


над a определен (+) => a -> a -> a


ВВ>Любую ситуацию с "нежданчиком" можно обработать — на основе данных, которые становятся доступны только в рантайме.


Ну так, упрощенно говоря, код, обрабатывающий "нежданчик" — и есть доказательство для теоремы, заданной в сигнатуре типа. Вот компилятор и проверяет обрабатываются ли все "нежданчики". А если такого кода нет — это баг.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[22]: Неправильное введение в функциональное программирование
От: Воронков Василий Россия  
Дата: 29.11.13 19:14
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Здравствуйте, Воронков Василий, Вы писали:

ВВ>>Никакой это не немерлизм. Это, может, в OCaml не так, где не потрудились ХМ допилить. А в языках с полиморфными операторами ты даже функцию "sum x y =x+y" иначе не типизируешь. Ибо какой у нее тип?

K>
K>над a определен (+) => a -> a -> a
K>


А что такое "а"? С чего ты решил, что функция полиморфная?

> let sum x y = x+y
sum "Hello," "there!";;

val sum : x:string -> y:string -> string
val it : string = "Hello,there!"

> let sum x y = x+y
sum 1 2;;

val sum : x:int -> y:int -> int
val it : int = 3


Да и, собственно, если даже она полиморфная, ее все равно компилировать как-то надо — хотя это уже другой вопрос.

Но на всякий случай повторюсь, чтобы не раздувать лишний флейм — речь шла о том, что "типизация по месту" это прямь какая-то кривь и немерлизм. Однако нет. Нормальная практика.

ВВ>>Любую ситуацию с "нежданчиком" можно обработать — на основе данных, которые становятся доступны только в рантайме.

K>Ну так, упрощенно говоря, код, обрабатывающий "нежданчик" — и есть доказательство для теоремы, заданной в сигнатуре типа. Вот компилятор и проверяет обрабатываются ли все "нежданчики". А если такого кода нет — это баг.

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

Или я не прав и круче зависимых типов только яйца?
Re[21]: Неправильное введение в функциональное программирование
От: VoidEx  
Дата: 29.11.13 20:32
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>
ВВ>x = 2
ВВ>


ВВ>Это тоже рантайм значение. Вот только известно оно в компайл-тайме.

ВВ>Повторяю — зависимость от рантайм-значений означает зависимость от значений, которые *известны* только в рантайме.

  args <- getArgs          -- читаем аргументы командной строки, рантайм значение
  let p = length args > 1


Вы не видите разницы? p — рантайм значение.
Ну и, просто повторите этот код на любом другом языке программирования.
Re[22]: Неправильное введение в функциональное программирование
От: Воронков Василий Россия  
Дата: 29.11.13 21:04
Оценка: :)
Здравствуйте, VoidEx, Вы писали:

VE>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>
ВВ>>x = 2
ВВ>>


ВВ>>Это тоже рантайм значение. Вот только известно оно в компайл-тайме.

ВВ>>Повторяю — зависимость от рантайм-значений означает зависимость от значений, которые *известны* только в рантайме.

VE>
VE>  args <- getArgs          -- читаем аргументы командной строки, рантайм значение
VE>  let p = length args > 1
VE>


VE>Вы не видите разницы? p — рантайм значение.

VE>Ну и, просто повторите этот код на любом другом языке программирования.

У p всего два возможных значения, оба известны в компайл и зависимости от рантайма тут нет.
Re: Неправильное введение в функциональное программирование
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 29.11.13 21:33
Оценка:
Здравствуйте, Воронков Василий Владимирович, Вы писали:

ВВВ>Аннотация:

ВВВ>В данном введении я не буду рассказывать об истории функциональных языков программирования. Я не буду писать о лямбда исчислении и комбинаторике. Я даже не буду убеждать читателя в том, что функциональное программирование – это полезно и важно. Наверняка вы уже неоднократно обо всем этом читали. У меня в данном случае несколько иная задача. Я постараюсь действительно ответить на некоторые вопросы, которые могли остаться у вас после прочтения других «введений». Это, конечно, не слишком соответствует традициям – отсюда и подобное название у этой статьи..


Func<int,int> sum(int x)
{
    return z => y => x + y + z;
}


Вот это не палит. Сигнатура должна быть Func<int, Func<int, int>>
Re: Неправильное введение в функциональное программирование
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 29.11.13 21:48
Оценка: +1 :)
Здравствуйте, Воронков Василий Владимирович, Вы писали:

ВВВ>Аннотация:

ВВВ>В данном введении я не буду рассказывать об истории функциональных языков программирования. Я не буду писать о лямбда исчислении и комбинаторике. Я даже не буду убеждать читателя в том, что функциональное программирование – это полезно и важно. Наверняка вы уже неоднократно обо всем этом читали. У меня в данном случае несколько иная задача. Я постараюсь действительно ответить на некоторые вопросы, которые могли остаться у вас после прочтения других «введений». Это, конечно, не слишком соответствует традициям – отсюда и подобное название у этой статьи..

Не совсем ясно, почему статья называется "неправильное введение", если у ней отличие от других материалов около нуля. Вопросы которые остаются после книг по ФП обычно навроде "для чего", "где подвох" и "как контролировать память и перформанс"
А у тебя как то скучно — "что это такое" только галопом по европам.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.