Ввод-вывод и чистые функции
От: AlexRK  
Дата: 23.01.17 19:44
Оценка:
Приветствую, уважаемые форумчане.

Есть два подхода к реализации ИО: как в большинстве мейнстримовых языков (в любой функции может быть чтение файла), или как в меньшинстве функциональных — сигнатура грязных функций "заражена" чем-то, например уникальным типом "мир" или чем-то в этом роде.

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

Вы за какой вариант, с явно видимым в сигнатуре функции вводом-выводом, а-ля Хаскель, или с неявным, а-ля Ц++? Почему?
Re: Ввод-вывод и чистые функции
От: deniok Россия  
Дата: 23.01.17 20:14
Оценка: 11 (1) -1
Здравствуйте, AlexRK, Вы писали:

ARK>Вы за какой вариант, с явно видимым в сигнатуре функции вводом-выводом, а-ля Хаскель, или с неявным, а-ля Ц++? Почему?


В Haskell:
(1) нет стека вызовов;
(2) нет типов в рантайме.
Так что засорять нечего и нечем.
Re[2]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 23.01.17 21:21
Оценка:
Здравствуйте, deniok, Вы писали:

ARK>>Вы за какой вариант, с явно видимым в сигнатуре функции вводом-выводом, а-ля Хаскель, или с неявным, а-ля Ц++? Почему?


D>В Haskell:

D>(1) нет стека вызовов;
D>(2) нет типов в рантайме.

Хорошо, пусть будет Clean, вопрос совершенно не в этом.

D>Так что засорять нечего и нечем.


Ну да, конечно же нечего и нечем.

https://www.haskell.org/tutorial/io.html

getChar :: IO Char


The return function admits an ordinary value such as a boolean to the realm of I/O actions. What about the other direction? Can we invoke some I/O actions within an ordinary expression? For example, how can we say x + print y in an expression so that y is printed out as the expression evaluates? The answer is that we can't! It is not possible to sneak into the imperative universe while in the midst of purely functional code. Any value `infected' by the imperative world must be tagged as such. A function such as

f :: Int -> Int -> Int

absolutely cannot do any I/O since IO does not appear in the returned type.

Re: Ввод-вывод и чистые функции
От: vsb Казахстан  
Дата: 23.01.17 21:26
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Вы за какой вариант, с явно видимым в сигнатуре функции вводом-выводом, а-ля Хаскель, или с неявным, а-ля Ц++? Почему?


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

Тут подумалось. В плохом Java-коде везде, где есть ввод-вывод, в сигнатурах пестрит throws IOException и он заставляет прокидывать этот throws дальше (ну или ловить, но это не интересный вариант). Может это на самом деле хороший код, который пишут хаскеллисты?
Отредактировано 23.01.2017 21:26 vsb . Предыдущая версия .
Re[2]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 23.01.17 21:32
Оценка:
Здравствуйте, vsb, Вы писали:

ARK>>Вы за какой вариант, с явно видимым в сигнатуре функции вводом-выводом, а-ля Хаскель, или с неявным, а-ля Ц++? Почему?


vsb>Я за явный, причины очевидны — о чистых функциях легко рассуждать, поэтому их должно быть как можно больше.


Я вот тоже всегда так думал, а сейчас что-то засомневался. Очень уж много вокруг ввода-вывода. Возможно, оптимальнее вариант языка D — по умолчанию функции грязные, но можно указать модификатор Pure? А даст ли это что-то существенное?

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


По идее, такие вещи можно отслеживать компилятором и без сигнатур (по-моему, в C# подобный анализ имеется). Сигнатуры функций — они больше для программиста, ИМХО.

vsb>Тут подумалось. В плохом Java-коде везде, где есть ввод-вывод, в сигнатурах пестрит throws IOException и он заставляет прокидывать этот throws дальше (ну или ловить, но это не интересный вариант). Может это на самом деле хороший код, который пишут хаскеллисты?


Хз, может в хаскелле это и считается хорошим кодом, но в жабе это выглядит как говно.
Re: Ввод-вывод и чистые функции
От: WolfHound  
Дата: 24.01.17 00:25
Оценка: 1 (1)
Здравствуйте, AlexRK, Вы писали:

ARK>Вот возник дурацкий вопрос. Засорение стека вызовов грязных функций специальным параметром — хорошая штука или не очень?

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

ARK>Если программа делает сплошной ввод-вывод, то это наверное не очень круто, а если ввода-вывода мало — то наоборот. Вроде как в основном в программах ввода-вывода много.

В программах, которые ты пишешь.
А в программах, которые пишу я ввод/вывод занимает ничтожную часть кода.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 24.01.17 06:40
Оценка:
Здравствуйте, WolfHound, Вы писали:

ARK>>Вот возник дурацкий вопрос. Засорение стека вызовов грязных функций специальным параметром — хорошая штука или не очень?

WH>Эти типы не имеют осмысленных рантайм значений. Так что компилятор не выделяет под них память и не генерирует для них код.
WH>Те эти типы дают проверки времени компиляции, не влияя на исполнение.

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

ARK>>Если программа делает сплошной ввод-вывод, то это наверное не очень круто, а если ввода-вывода мало — то наоборот. Вроде как в основном в программах ввода-вывода много.

WH>В программах, которые ты пишешь.
WH>А в программах, которые пишу я ввод/вывод занимает ничтожную часть кода.

Вот меня и интересует, а каких программ больше — каких пишу я или каких пишете вы. По-моему, первое.
Re[2]: Ввод-вывод и чистые функции
От: Слава  
Дата: 24.01.17 08:34
Оценка:
Здравствуйте, WolfHound, Вы писали:

ARK>>Если программа делает сплошной ввод-вывод, то это наверное не очень круто, а если ввода-вывода мало — то наоборот. Вроде как в основном в программах ввода-вывода много.

WH>В программах, которые ты пишешь.
WH>А в программах, которые пишу я ввод/вывод занимает ничтожную часть кода.

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

INB4: си!
Re[3]: Ввод-вывод и чистые функции
От: deniok Россия  
Дата: 24.01.17 09:00
Оценка:
Здравствуйте, AlexRK, Вы писали:

D>>Так что засорять нечего и нечем.


ARK>Ну да, конечно же нечего и нечем.


ARK>https://www.haskell.org/tutorial/io.html


ARK>

getChar :: IO Char


ARK>

The return function admits an ordinary value such as a boolean to the realm of I/O actions. What about the other direction? Can we invoke some I/O actions within an ordinary expression? For example, how can we say x + print y in an expression so that y is printed out as the expression evaluates? The answer is that we can't! It is not possible to sneak into the imperative universe while in the midst of purely functional code. Any value `infected' by the imperative world must be tagged as such. A function such as

ARK>f :: Int -> Int -> Int

ARK>absolutely cannot do any I/O since IO does not appear in the returned type.


Так это же не метка IO засоряет программу! Ее засоряет сам факт ввода-вывода. А монада IO как раз приводит хаос ввода-вывода к стандартному для Хаскеля монадическому интерфейсу работы с эффектами.

Если же просто использовать такую метку без механизма, дающего какой-то разумный набор гарантий, то толку от нее действительно мало.
Re[4]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 24.01.17 09:11
Оценка:
Здравствуйте, deniok, Вы писали:

D>Так это же не метка IO засоряет программу! Ее засоряет сам факт ввода-вывода. А монада IO как раз приводит хаос ввода-вывода к стандартному для Хаскеля монадическому интерфейсу работы с эффектами.


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

D>Если же просто использовать такую метку без механизма, дающего какой-то разумный набор гарантий, то толку от нее действительно мало.


Разумеется, речь идет о предоставлении гарантий. Только вот существует куча языков, в которых и без этой метки всё работает.

В данной теме я как раз поднял вопрос, а как "правильно"-то? С меткой или без? Кто что думает по этому поводу? То, что в природе успешно существуют оба варианта, я в курсе.
Re: Ввод-вывод и чистые функции
От: novitk США  
Дата: 27.01.17 18:22
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Вы за какой вариант, с явно видимым в сигнатуре функции вводом-выводом, а-ля Хаскель, или с неявным, а-ля Ц++? Почему?


Проблема имхо не в сигнатуре функции, тут как раз все хорошо, а в самом коде где нужно явно делать лифтинг в монаду, через все эти liftM, foldM, etc. Это сильно засоряет код и мешает пониманию. Я не спец в системах типов, но возможно в будущем можно сделать что-то для автоматизации процесса. Например, если есть

foobar: IO a
pure: a -> b

можно будет просто написать "pure.foobar", как в нечистых языках или близко к тому, и компилятор сам подставит нужный lift.
Re[2]: Ввод-вывод и чистые функции
От: deniok Россия  
Дата: 27.01.17 18:31
Оценка:
Здравствуйте, novitk, Вы писали:


N>foobar: IO a

N>pure: a -> b

N>можно будет просто написать "pure.foobar", как в нечистых языках или близко к тому, и компилятор сам подставит нужный lift.


pure <$> foobar
Re[3]: Ввод-вывод и чистые функции
От: novitk США  
Дата: 27.01.17 18:42
Оценка:
Здравствуйте, deniok, Вы писали:

D>
D>pure <$> foobar
D>


Я как бы в курсе, но хотелось бы избавиться, то есть чтобы компилятор это сам выводил.
Re[4]: Ввод-вывод и чистые функции
От: deniok Россия  
Дата: 27.01.17 19:07
Оценка:
Здравствуйте, novitk, Вы писали:

N>Здравствуйте, deniok, Вы писали:


D>>
D>>pure <$> foobar
D>>


N>Я как бы в курсе, но хотелось бы избавиться, то есть чтобы компилятор это сам выводил.


Это плохо совместимо с общим механизмом вывода типов в Хаскеле. Что он должен вывести для const foobar, если не сможет различать вызовы c лифтингом и без
> {foobar::IO a; foobar = undefined}
> :t const foobar
const foobar :: b -> IO a
> :t const <$> foobar
const <$> foobar :: IO (b -> a)
Re[5]: Ввод-вывод и чистые функции
От: novitk США  
Дата: 27.01.17 19:40
Оценка:
Здравствуйте, deniok, Вы писали:

D>Это плохо совместимо с общим механизмом вывода типов в Хаскеле. Что он должен вывести для const foobar, если не сможет различать вызовы c лифтингом и без


Согласен, на существующей системе оно неоднозначно, но помечтать то не возбраняется. То есть я, как стратег, задачу ставлю, а вы тактики ее решайте
Если серьезно, то у меня нет идей и подготовки, что можно с этим сделать. Сам по себе <$> может и ок, но вот весь зоопарк в Functor/Applicative/Monad сильно интрузивен.
Re[2]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 27.01.17 20:07
Оценка:
Здравствуйте, novitk, Вы писали:

ARK>>Вы за какой вариант, с явно видимым в сигнатуре функции вводом-выводом, а-ля Хаскель, или с неявным, а-ля Ц++? Почему?


N>Проблема имхо не в сигнатуре функции, тут как раз все хорошо, а в самом коде где нужно явно делать лифтинг в монаду, через все эти liftM, foldM, etc.


Ну, в языке D есть pure-функции, но при этом никаких лифтингов ни в какие монады там делать не надо.
Re[2]: Ввод-вывод и чистые функции
От: WolfHound  
Дата: 28.01.17 04:15
Оценка:
Здравствуйте, novitk, Вы писали:

N>Проблема имхо не в сигнатуре функции, тут как раз все хорошо, а в самом коде где нужно явно делать лифтинг в монаду, через все эти liftM, foldM, etc. Это сильно засоряет код и мешает пониманию. Я не спец в системах типов, но возможно в будущем можно сделать что-то для автоматизации процесса. Например, если есть

Такое?
https://koka-lang.github.io/koka/doc/kokaspec.html#sec-polymorphic-effects
Эффекты это считай обобщение монад.
Разница в том, что монада одна, а эффектов может быть много. Или вообще не быть.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Ввод-вывод и чистые функции
От: WolfHound  
Дата: 28.01.17 04:22
Оценка: +3
Здравствуйте, AlexRK, Вы писали:

ARK>Это я знаю. Вопрос не в этом. Вопрос таков — засорение самого кода программы ухудшает читабельность или все-таки что-то дает?

1)Ловит ошибки.
2)Улучшает читаемость кода.
3)Развязывает руки оптимизатору.

ARK>Вот меня и интересует, а каких программ больше — каких пишу я или каких пишете вы. По-моему, первое.

Есть конечно программы, которые сильно тяготеют в одну или другую сторону. Но во многих случаях зависит от того как у разработчиков программы мозги устроены.
Я в любом случае стараюсь минимизировать и изолировать ИО. Так программу легче понимать.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Ввод-вывод и чистые функции
От: Nick Linker Россия lj://_lcr_
Дата: 28.01.17 09:29
Оценка:
AlexRK,

ARK>>>Вы за какой вариант, с явно видимым в сигнатуре функции вводом-выводом, а-ля Хаскель, или с неявным, а-ля Ц++? Почему?


N>>Проблема имхо не в сигнатуре функции, тут как раз все хорошо, а в самом коде где нужно явно делать лифтинг в монаду, через все эти liftM, foldM, etc.


ARK>Ну, в языке D есть pure-функции, но при этом никаких лифтингов ни в какие монады там делать не надо.


Но тогда скажем функция `map` в D чистая или нет? Как D мне запретит туда передать лямбду `println(_)`? А если запрещает, как мне тогда всё же передать `prinln()`?

В хаскеле связь между монадами и грязными функциями напрямую отсутствует, непосредственно io-эффекты несёт с собой только монада IO, но при этом сам хаскель про это не знает.
Вот, например, это чистая функция, хотя я могу определить её в монаде Maybe:
fold2 :: Maybe a -> Maybe b -> (a -> b -> c) -> Maybe c
fold2 mba mbb f = do
  a <- mba
  b <- mbb
  return $ f a b

--test it
λ> fold2 (Just 10) (Just 20) (+)
Just 30


Или, например, есть функция `mapM :: (Monad m, Traversable t) => (a -> m b) -> t a -> m (t b)`, которая внезапно одновременно и чистая, и грязная:
λ> mapM print [1,2,3]
1
2
3
[(),(),()]

λ> mapM Just [1,2,3]
Just [1,2,3]


А вот ещё пример чистой (!) функции, которая читает из и пишет в KV-сторадж и даже делает это в транзакции:
type Ops = Free OpsF

foo :: Ops (Map Key Val)
foo = do
  let k1 = "foo1"
  let k2 = "foo2"
  put k1 "value1"
  put k2 "value2"
  transact $ do
    (vt1, vt2) <- transact $ do
      v1 <- get k1
      v2 <- get k2
      return (v1, v2)
    transact $ do
      put k1 vt2
      put k2 vt1
  -- get one by one, not in transaction
  vn1 <- get k1
  vn2 <- get k2
  return $
    insert k1 vn1 $
    insert k2 vn2 empty


Парадокс?
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[4]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 28.01.17 10:45
Оценка:
Здравствуйте, Nick Linker, Вы писали:

NL>Но тогда скажем функция `map` в D чистая или нет?


Понятия не имею, возможно есть два варианта этой функции.

NL>Как D мне запретит туда передать лямбду `println(_)`?


Не скомпилирует код.

NL>А если запрещает, как мне тогда всё же передать `prinln()`?


Никак. Это все равно что задать вопрос "как мне передать в функцию строку, в то время как функция требует число".

NL>Парадокс?


Просто другой подход, а вот лучше он или хуже — вопрос остается открытым.
Re[5]: Ввод-вывод и чистые функции
От: novitk США  
Дата: 28.01.17 14:28
Оценка:
Здравствуйте, AlexRK, Вы писали:

NL>>Но тогда скажем функция `map` в D чистая или нет?

ARK>Понятия не имею, возможно есть два варианта этой функции.

Похоже они там просто не додумали.
http://stackoverflow.com/questions/5812186/pure-functional-programming-in-d

Unfortunately the interaction between generic code and pure (as well as const and immutable) is rather poor. There have been several proposals to fix this, but none have been accepted yet.
\std.algorithm is written to be as generic as possible, so it can't require that its lambda functions and the ranges it accepts be pure. Furthermore, the type system features that were added in D2 are generally the most buggy features in the language, because more basic things have been prioritized ahead of fixing the relevant issues. Right now, pure is basically not usable except for trivial cases like std.math.

Re[4]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 28.01.17 14:43
Оценка:
Здравствуйте, Nick Linker, Вы писали:

NL>Но тогда скажем функция `map` в D чистая или нет? Как D мне запретит туда передать лямбду `println(_)`? А если запрещает, как мне тогда всё же передать `prinln()`?


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

Это всё следствия более общего вопроса в построение языка: мультипарадигменный он или нет. Современные удобные языки легко позволяют писать и в ООП стиле и ФП стиле и даже закопаться в МП. А можно смешать это всё в одном проекте и всё равно всё будет удобно. Именно поэтому у языка D (сильно мультипарадигменного) есть хоть какие-то шансы на большой успех (там уже больше от "политики" зависит), а у того же однопарадигменного Хаскеля таких шансов не было от рождения.

Это естественно речь о языках общего назначения. Для всяких всяческих DSL'ей однопарадигменность может быть вполне удобна.
Re[6]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 28.01.17 15:01
Оценка:
Здравствуйте, novitk, Вы писали:

N>Похоже они там просто не додумали.

N>http://stackoverflow.com/questions/5812186/pure-functional-programming-in-d
N>

N>Unfortunately the interaction between generic code and pure (as well as const and immutable) is rather poor. There have been several proposals to fix this, but none have been accepted yet.
N>\std.algorithm is written to be as generic as possible, so it can't require that its lambda functions and the ranges it accepts be pure. Furthermore, the type system features that were added in D2 are generally the most buggy features in the language, because more basic things have been prioritized ahead of fixing the relevant issues. Right now, pure is basically not usable except for trivial cases like std.math.


Ерунда тут написана. Да, вся стандартная библиотека языка построена вокруг метапрограммирования (даже в большей степени чем STL в C++). Но при этом работа с атрибутами типов (в том числе и pure) легко доступна из этого самого МП — не требуются никакие доработки, уже всё отлично работает. Т.е. нет вообще никакой проблемы в написание обобщённой map с требованием на pure.

Другое дело (и это справедливо отмечено в заданном на SO вопросе), что реализации алгоритмов из стандартной библиотеки в данный момент ни сами не отмечены как pure, ни требуют этого от передаваемых в них функций. Правильно это или нет — это другой вопрос, зависящий на мой взгляд от того, какого больше стиля придерживается усреднённый программист на D. Но в любом случае у желающего есть все возможности сделать любой вариант. Ну и да, наверное в идеале в будущем иметь в стандартной библиотеке все возможные реализации. )
Re[6]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 28.01.17 15:08
Оценка:
Здравствуйте, novitk, Вы писали:

N>Похоже они там просто не додумали.


Не знаю, что там можно додумать. Тут либо оставить всё как есть (просто помечать функции как чистые), либо пихать в каждый вызов какую-то шнягу, запрещающую считать вызов ссылочно прозрачным.
Re[7]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 28.01.17 15:13
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Другое дело (и это справедливо отмечено в заданном на SO вопросе), что реализации алгоритмов из стандартной библиотеки в данный момент ни сами не отмечены как pure, ни требуют этого от передаваемых в них функций.


Изначальный вопрос
Автор: Nick Linker
Дата: 28.01.17
как раз и был именно об этом.

_>Правильно это или нет — это другой вопрос, зависящий на мой взгляд от того, какого больше стиля придерживается усреднённый программист на D. Но в любом случае у желающего есть все возможности сделать любой вариант. Ну и да, наверное в идеале в будущем иметь в стандартной библиотеке все возможные реализации. )


В этой ветке как раз и мусолится вариант, что хорошо бы иметь функцию, подходящую "ко всему" — хоть к пуре, хоть к унпуре коду. Только вот лично мне пока не вполне ясно, как это можно (и можно ли) сделать просто (а не нагородив адской хрени а-ля Хаскель).
Re[8]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 28.01.17 15:46
Оценка:
Здравствуйте, AlexRK, Вы писали:

_>>Правильно это или нет — это другой вопрос, зависящий на мой взгляд от того, какого больше стиля придерживается усреднённый программист на D. Но в любом случае у желающего есть все возможности сделать любой вариант. Ну и да, наверное в идеале в будущем иметь в стандартной библиотеке все возможные реализации. )

ARK>В этой ветке как раз и мусолится вариант, что хорошо бы иметь функцию, подходящую "ко всему" — хоть к пуре, хоть к унпуре коду. Только вот лично мне пока не вполне ясно, как это можно (и можно ли) сделать просто (а не нагородив адской хрени а-ля Хаскель).

В Хаскеле адская хрень исключительно потому, что там формально просто нет "не чистых" функций. ))) Это так сказать "язык с высокими принципами", а потому обречённый на маргинальное существование.

А в D как раз этим проблем нет: стандартный библиотечный map спокойно проглотит функцию и с модификатором pure и без него. Как ты и хочешь.

Другое дело, если ты хочешь какую-то отдельную реализацию для map с pure. Такое тоже элементарно делается в D (там же всё на МП). Более того, подобный код очень распространён в стандартной библиотеке, только не для pure, а для другого: во многих стандартных алгоритмах можно увидеть несколько разных реализации, а выбор нужной ветки происходит в зависимости от типа доступа к обрабатываем данным (например только последовательный доступ (подходит для всех случаев, но медленный) или же есть возможность произвольного(тогда алгоритм эффективнее)). Однако для pure мне пока не приходит в голову какая может быть от этого польза. В принципе гарантированная чистота функции даёт две известные дополнительные возможности при её использование: ленивость и мемоизация. Однако скажем для того же map эти возможности вряд ли применимы на практике, так что по идее код map не должен отличаться для чистых и не чистых функций.

Ну и плюс для особых фанатов строгости можно в две строчки определить свой my_map, который будет работать в точности как стандартный, но при этом иметь ограничение на чистоту передаваемой функции (т.е. компилятор будет ругаться, если передашь в my_map не чистую функцию).
Re[9]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 28.01.17 15:58
Оценка:
Здравствуйте, alex_public, Вы писали:

_>А в D как раз этим проблем нет: стандартный библиотечный map спокойно проглотит функцию и с модификатором pure и без него. Как ты и хочешь.


Если я верно понимаю, то это всего лишь значит, что map там грязный. Понятно, что грязная функция что угодно проглотит.

_>Другое дело, если ты хочешь какую-то отдельную реализацию для map с pure. Такое тоже элементарно делается в D (там же всё на МП).


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

_>Более того, подобный код очень распространён в стандартной библиотеке, только не для pure, а для другого: во многих стандартных алгоритмах можно увидеть несколько разных реализации, а выбор нужной ветки происходит в зависимости от типа доступа к обрабатываем данным (например только последовательный доступ (подходит для всех случаев, но медленный) или же есть возможность произвольного(тогда алгоритм эффективнее)).


Это все же другое, это особенности реализации функции. А для pure/unpure нам нужно две разных функции.

_>Однако для pure мне пока не приходит в голову какая может быть от этого польза. В принципе гарантированная чистота функции даёт две известные дополнительные возможности при её использование: ленивость и мемоизация. Однако скажем для того же map эти возможности вряд ли применимы на практике, так что по идее код map не должен отличаться для чистых и не чистых функций.


ИМХО, самое главное свойство — ссылочная прозрачность. Возможность заменить функцию от известных аргументов уже вычисленным значением. Чтобы сделать это с map, нам нужно два ограничения: сам map не должен содержать ввода-вывода (то бишь быть pure), плюс передаваемая в него функция тоже должна быть pure.

Таким образом, получаем два мапа — один чистый, один грязный. Кривовато...
Re[10]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 29.01.17 14:39
Оценка:
Здравствуйте, AlexRK, Вы писали:

_>>А в D как раз этим проблем нет: стандартный библиотечный map спокойно проглотит функцию и с модификатором pure и без него. Как ты и хочешь.

ARK>Если я верно понимаю, то это всего лишь значит, что map там грязный. Понятно, что грязная функция что угодно проглотит.

И да и нет.

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

_>>Более того, подобный код очень распространён в стандартной библиотеке, только не для pure, а для другого: во многих стандартных алгоритмах можно увидеть несколько разных реализации, а выбор нужной ветки происходит в зависимости от типа доступа к обрабатываем данным (например только последовательный доступ (подходит для всех случаев, но медленный) или же есть возможность произвольного(тогда алгоритм эффективнее)).

ARK>Это все же другое, это особенности реализации функции. А для pure/unpure нам нужно две разных функции.

Просто в D в силу развитого МП и наличия статической интроспекции частенько вместо использования перегрузки функции по типу аргумента применяется обобщённый аргумент, а где-то внутри тела функции размещено ветвление (отрабатывающее во время компиляции) на базе анализа типов аргументов.

ARK>Таким образом, получаем два мапа — один чистый, один грязный. Кривовато...


Ну как бы а какие ещё варианты? ) В других языках и такого нет. )))

Вообще я бы сделал одно исправление в механике работы D в этом смысле. Сейчас (во всяком случае на тот момент, когда я игрался с D — может за пару последних лет что-то и поменялось) атрибут pure устанавливается программистов и потом проверяется компилятором (если функция не удовлетворяет нужным условиям, то получаем ошибку компиляции). А бы предложил сделать наоборот: чтобы компилятор сам проверял все функции на предмет чистоты и в случае удовлетворения требований сам проставлял бы этот атрибут.

Если сделать такое изменение, то можно и расставить требование на pure во многих местах библиотеки. Потому что при таком раскладе оно не будет напрягать классических "императивных" программистов, которые не в курсе ни про какие pure и не собираются их использовать в своём коде.
Re[3]: Ввод-вывод и чистые функции
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.17 22:52
Оценка:
Здравствуйте, Слава, Вы писали:

С>Тогда можно задать вопрос, а существуют ли хорошие и современные языки для программ, занимающихся в основном вводом-выводом.


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

Я вам один секрет открою. У функциональных языков нет никаких проблем с вводом выводом. Проблемы есть у ленивых языков. По жизни таких не так много. Хаскель и пара экспериментальных. Проблемы у них проистекают из того, что у них:
1. Порядок вычислений не проистекает из расположения выражений в коде.
2. Выполнение отложенное и может просто не производиться, если результат не нужен.

Если ФЯ является энергичным, то побочные эффекты в функциях работают так же как и в императивном языке. scala, Nemerle, F#, Ocaml и куча других языков не имеют никаких проблем с побочными эффектами.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 30.01.17 08:09
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Она грязная с точки зрения отсутствия соответствующих атрибутов. Но сама то по построению очевидно чистая. Так что соответственно если передать в неё чистые аргументы, то и вся конструкция окажется чистой (опять же по построению, а не атрибутам типа).


Верно. Но мы таким образом теряем возможность рассуждать о свойствах программы, глядя в ее код. Видим где-то в середине шаблонного кода вызов map, но чистый он или нет — понять нельзя. Собственно, откуда мы вообще знаем, что map "чистый по построению"? Только посмотрев в исходники (а если их нет?). И если завтра Брайту взбредет в голову сунуть в map чтение файла, мы этого никак не заметим и компилятор нам ничего не скажет. Вот в этом проблема "чистоты по построению". Хотя эта проблема может выглядеть надуманной, мне она кажется весьма важной.

ARK>>Таким образом, получаем два мапа — один чистый, один грязный. Кривовато...

_>Ну как бы а какие ещё варианты? ) В других языках и такого нет. )))

Ну, вон в том же Хаскеле есть другой вариант — когда всё вокруг как будто чистое, но побочный эффект каким-то образом упаковывается в передаваемое внутрь значение и чистая функция как бы и ни при чем — ее эффект приплюсовывается поверх побочного эффекта и потом вся эта хрень выполняется грязным рантаймом (если я правильно понимаю идеологию). Но вот не уверен, что вся эта овчинка стоит выделки.

_>Вообще я бы сделал одно исправление в механике работы D в этом смысле. Сейчас (во всяком случае на тот момент, когда я игрался с D — может за пару последних лет что-то и поменялось) атрибут pure устанавливается программистов и потом проверяется компилятором (если функция не удовлетворяет нужным условиям, то получаем ошибку компиляции). А бы предложил сделать наоборот: чтобы компилятор сам проверял все функции на предмет чистоты и в случае удовлетворения требований сам проставлял бы этот атрибут.


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

_>Если сделать такое изменение, то можно и расставить требование на pure во многих местах библиотеки. Потому что при таком раскладе оно не будет напрягать классических "императивных" программистов, которые не в курсе ни про какие pure и не собираются их использовать в своём коде.


Вот тут не очень понял. Если pure уже проставлено, то чего с ним еще можно сделать? Или имеется в виду, что модификатор "pure" может быть при необходимости отменен компилятором, если он видит возможность нечистого вызова? Тогда опять же с такого модификатора нет особого толка, если он не дает гарантий...

UPD. А, кажется понял. Вы имеете в виду, что pure будет гарантировать именно ту самую "чистоту по построению", но не чистоту самого вызова. В принципе да, это неплохо.



В общем, по большому счету есть немного вариантов:
1) "железобетонное" pure — приходим к необходимости дублировать некоторые функции в чистом и грязном виде;
2) "мягкое" pure — необходимо учитывать весь контекст вызова, чтобы точно знать, pure оно или нет;
3) оверинженернутый подход а-ля Хаскель — приводит к распространению по коду "лифтингов";
4) вообще никакого контроля а-ля C/C++.

Криво — всё.

Лично мне из всех зол пока почему-то больше нравится вариант 1. Хотя, после некоторых размышлений, вариант 2 может быть даже и лучше.
Отредактировано 30.01.2017 8:21 AlexRK . Предыдущая версия .
Re[12]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 30.01.17 14:55
Оценка:
Здравствуйте, AlexRK, Вы писали:

_>>Она грязная с точки зрения отсутствия соответствующих атрибутов. Но сама то по построению очевидно чистая. Так что соответственно если передать в неё чистые аргументы, то и вся конструкция окажется чистой (опять же по построению, а не атрибутам типа).

ARK>Верно. Но мы таким образом теряем возможность рассуждать о свойствах программы, глядя в ее код. Видим где-то в середине шаблонного кода вызов map, но чистый он или нет — понять нельзя. Собственно, откуда мы вообще знаем, что map "чистый по построению"? Только посмотрев в исходники (а если их нет?). И если завтра Брайту взбредет в голову сунуть в map чтение файла, мы этого никак не заметим и компилятор нам ничего не скажет. Вот в этом проблема "чистоты по построению". Хотя эта проблема может выглядеть надуманной, мне она кажется весьма важной.

Не, я согласен что явная аннотация важна. Я просто подчеркнул, что "грязнота" стандартного библиотечного map'а как раз и заключается только в отсутствие этой самой аннотации.

ARK>Ну, вон в том же Хаскеле есть другой вариант — когда всё вокруг как будто чистое, но побочный эффект каким-то образом упаковывается в передаваемое внутрь значение и чистая функция как бы и ни при чем — ее эффект приплюсовывается поверх побочного эффекта и потом вся эта хрень выполняется грязным рантаймом (если я правильно понимаю идеологию). Но вот не уверен, что вся эта овчинка стоит выделки.


Хаскель имеет право на существование исключительно как некий экспериментальный язык, на котором можно изучать различные новые идей в данной области.

_>>Вообще я бы сделал одно исправление в механике работы D в этом смысле. Сейчас (во всяком случае на тот момент, когда я игрался с D — может за пару последних лет что-то и поменялось) атрибут pure устанавливается программистов и потом проверяется компилятором (если функция не удовлетворяет нужным условиям, то получаем ошибку компиляции). А бы предложил сделать наоборот: чтобы компилятор сам проверял все функции на предмет чистоты и в случае удовлетворения требований сам проставлял бы этот атрибут.

ARK>Под "проставлял" имеется в виду не в смысле физически менял код, а просто учитывал это при оптимизациях? Ну, такое давно везде есть, по-моему. И, собственно, теряется главное преимущество явных пометок — возможность рассуждать о коде (о чем я писал выше).

Менял не код, а прототип функции (pure — это же атрибут типа). Который потом учитывается другими функциями (принимающими данную как параметр и т.п.).

_>>Если сделать такое изменение, то можно и расставить требование на pure во многих местах библиотеки. Потому что при таком раскладе оно не будет напрягать классических "императивных" программистов, которые не в курсе ни про какие pure и не собираются их использовать в своём коде.

ARK>Вот тут не очень понял. Если pure уже проставлено, то чего с ним еще можно сделать? Или имеется в виду, что модификатор "pure" может быть при необходимости отменен компилятором, если он видит возможность нечистого вызова? Тогда опять же с такого модификатора нет особого толка, если он не дает гарантий...

Нет, идея в том чтобы атрибут pure был в прототипе не только тех функций, где это проставил программист, но и у тех, которые просто удовлетворяют этому условию (но программист поленился поставить). Поясняю почему это важно:

Допустим у нас есть библиотечная функция X(F f), принимающая некую пользовательскую функцию. Идеологически f обязательно должна быть чистой, но в нашей стандартной библиотеке это требование не стоит (по историческим и политическим причинам, типа как сейчас в библиотеке D) и X принимает любые функции. Чем прикладные программисты активно пользуются, передавая в X свои функции f произвольного вида (и чистые и не чистые, но в любом случае все без атрибута pure, т.к. всем пофиг на него).

Теперь если мы при нынешней работе компилятора изменим прототип X так, что он будет требовать только pure F, то это сломает вообще весь прикладной код всех программистов, включая абсолютно корректный.

А если бы компилятор работал так, как описал, то введение такого требования для X сломало бы только код тех программистов, которые передавали в X функции с наличием побочных эффектов (т.е. по сути сломался бы как раз некорректный изначально код).

ARK>В общем, по большому счету есть немного вариантов:

ARK>1) "железобетонное" pure — приходим к необходимости дублировать некоторые функции в чистом и грязном виде;
ARK>2) "мягкое" pure — необходимо учитывать весь контекст вызова, чтобы точно знать, pure оно или нет;
ARK>3) оверинженернутый подход а-ля Хаскель — приводит к распространению по коду "лифтингов";
ARK>4) вообще никакого контроля а-ля C/C++.
ARK>Криво — всё.
ARK>Лично мне из всех зол пока почему-то больше нравится вариант 1. Хотя, после некоторых размышлений, вариант 2 может быть даже и лучше.

Я пока что особо серьёзно не раздумывал об этой проблеме. Но в одном я уверен точно: подобное решение должно быть опциональным (например как в D), а не навязываемым.
Re[13]: Ввод-вывод и чистые функции
От: novitk США  
Дата: 30.01.17 16:00
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Не, я согласен что явная аннотация важна. Я просто подчеркнул, что "грязнота" стандартного библиотечного map'а как раз и заключается только в отсутствие этой самой аннотации.


А зачем ты это подчеркнул? В чем принципиальная важность? Если map грязный, то все что его использует тоже грязно, а это 99% кода, за исключением какой-то изолированной математики. И два map-a это не решение проблемы, потому что потом нужно два fold-а и вообще всего в std.algorithm или как оно там называется, и в результате ты получаешь тот же Хаскель с другой стороны.
Re[13]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 30.01.17 16:24
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Нет, идея в том чтобы атрибут pure был в прототипе не только тех функций, где это проставил программист, но и у тех, которые просто удовлетворяют этому условию (но программист поленился поставить). Поясняю почему это важно:


А, теперь понятно. Такие функции автоматом пролезают в pure-места даже без соответствующей пометки. То бишь это разновидность моего пункта 1, только без требования расставлять везде модификатор "pure". В принципе звучит разумно. Хотя недостатки остаются — необходимость иметь по два варианта каждой функции, которая может быть вызвана как в pure, так и unpure контексте.
Re[12]: Ввод-вывод и чистые функции
От: Слава  
Дата: 30.01.17 16:54
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>В общем, по большому счету есть немного вариантов:

ARK>1) "железобетонное" pure — приходим к необходимости дублировать некоторые функции в чистом и грязном виде;
ARK>2) "мягкое" pure — необходимо учитывать весь контекст вызова, чтобы точно знать, pure оно или нет;
ARK>3) оверинженернутый подход а-ля Хаскель — приводит к распространению по коду "лифтингов";
ARK>4) вообще никакого контроля а-ля C/C++.

5) Навешивать на функции пред- и пост- условия, наподобие, как это сделано в Ada Spark. Они дают более широкие гарантии, не только "чистота/не чистота".
Re[13]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 30.01.17 16:59
Оценка:
Здравствуйте, Слава, Вы писали:

С>Здравствуйте, AlexRK, Вы писали:


ARK>>В общем, по большому счету есть немного вариантов:

ARK>>1) "железобетонное" pure — приходим к необходимости дублировать некоторые функции в чистом и грязном виде;
ARK>>2) "мягкое" pure — необходимо учитывать весь контекст вызова, чтобы точно знать, pure оно или нет;
ARK>>3) оверинженернутый подход а-ля Хаскель — приводит к распространению по коду "лифтингов";
ARK>>4) вообще никакого контроля а-ля C/C++.

С>5) Навешивать на функции пред- и пост- условия, наподобие, как это сделано в Ada Spark. Они дают более широкие гарантии, не только "чистота/не чистота".


Это эквивалентно пункту 1.
Re[14]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 30.01.17 20:48
Оценка:
Здравствуйте, novitk, Вы писали:

_>>Не, я согласен что явная аннотация важна. Я просто подчеркнул, что "грязнота" стандартного библиотечного map'а как раз и заключается только в отсутствие этой самой аннотации.

N>А зачем ты это подчеркнул? В чем принципиальная важность? Если map грязный, то все что его использует тоже грязно, а это 99% кода, за исключением какой-то изолированной математики.

С чего бы это? Как раз map в 99% кода используют как чистую функцию (просто потому что для грязных императивных целей есть гораздо более удобный foreach). Только вот:

1. Это никак формально не гарантируется компилятором (а вот в D это добавили)
2. Факт данной чистоты никак потом на практике не используется (в том числе и в D, причём скорее вследствие отсутствия соответствующих навыков у прикладных программистов).

N>И два map-a это не решение проблемы, потому что потом нужно два fold-а и вообще всего в std.algorithm или как оно там называется,


Ну как бы вообще говоря решение. Только совсем не изящное.

N>и в результате ты получаешь тот же Хаскель с другой стороны.


В том то и дело что нет. У Хаскеля тоже развито только одно направление. Просто оно противоположное классическим императивным языкам. А вот языка с развитыми обоими направлениями что-то не видно пока. В D заложена потенциальная возможность этого. Но на практике (в библиотеках, в прикладном коде) она почти не используется.
Re[15]: Ввод-вывод и чистые функции
От: novitk США  
Дата: 30.01.17 22:23
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Не, я согласен что явная аннотация важна.

_>1. Это никак формально не гарантируется компилятором (а вот в D это добавили)
_>2. Факт данной чистоты никак потом на практике не используется (в том числе и в D, причём скорее вследствие отсутствия соответствующих навыков у прикладных программистов).
От меня ускользает смысл. ТС вроде за аннотацию, ты вроде тоже. 99% в D это обычные грязные функции без аннотации и написать на нем чистую функцию реально нельзя, так как комбинаторы тянут грязь. То есть по факту pure в нем не додумана и не используется.

N>>И два map-a это не решение проблемы, потому что потом нужно два fold-а и вообще всего в std.algorithm или как оно там называется,

_>Ну как бы вообще говоря решение. Только совсем не изящное.
int f(int i) pure {
    return i*i;
}
int h(int i) {
    writeln("Bad");
    return i*i;
}
int g(int function(int) pure func) pure {
    return func(10);
}
void main(string[ ] args)
{
   writeln(g(&f)); //no prob
   writeln(g(&h)); //???
}

main.d(18): Error: function main.g (int function(int) pure func) is not callable using argument types (int function(int i))
Как мне g переделать в грязную? Я надеюсь какой-то лифтинг все же есть и мне не надо переписывать g еще раз.

_>В D заложена потенциальная возможность этого. Но на практике (в библиотеках, в прикладном коде) она почти не используется.

Если функционал не используется, то в нем нет смысла. Пока есть сильное подозрение что авторы этой фичи в D просто не додумкали и/или не разобрались с матаном.
Re[4]: Ввод-вывод и чистые функции
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 31.01.17 07:36
Оценка: 14 (2)
Здравствуйте, Nick Linker, Вы писали:

ARK>>Ну, в языке D есть pure-функции, но при этом никаких лифтингов ни в какие монады там делать не надо.


NL>Но тогда скажем функция `map` в D чистая или нет? Как D мне запретит туда передать лямбду `println(_)`? А если запрещает, как мне тогда всё же передать `prinln()`?


Тут какой-то ерунды наговорили. В D map это не функция, это шаблон функции, генерик. Для шаблонов всегда работает автоматический вывод атрибутов, в том числе чистоты. Если в map передать чистую функцию, получится чистая функция. Если передать грязную — получится грязная.

import std.stdio, std.algorithm;

void myDirtyFun() { // используем map в грязной ф-ии
    auto xs = [1,2,3].map!((x) { write(x, " "); return x*2; }); 
    writeln(xs.sum);    
}

int myPureFun() pure { // используем map в чистой ф-ии
    auto xs = [1,2,3].map!(x => x*2);
    //write("hi"); // если раскомментировать, компилятор ругнется:
    // Error: pure function 'main.myPureFun' cannot call impure function 'std.stdio.write!string.write'
    return xs.sum;
}

void main(string[] argv) {
    myDirtyFun(); // 1 2 3 12
    writeln( myPureFun() ); // 12
}

https://dpaste.dzfl.pl/42460904b633
Re[7]: Ввод-вывод и чистые функции
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 31.01.17 07:39
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Другое дело (и это справедливо отмечено в заданном на SO вопросе), что реализации алгоритмов из стандартной библиотеки в данный момент ни сами не отмечены как pure, ни требуют этого от передаваемых в них функций. Правильно это или нет — это другой вопрос, зависящий на мой взгляд от того, какого больше стиля придерживается усреднённый программист на D. Но в любом случае у желающего есть все возможности сделать любой вариант. Ну и да, наверное в идеале в будущем иметь в стандартной библиотеке все возможные реализации. )


Там уже есть все реализации автоматически. В стандартной библиотеке все на шаблонах, передаешь чистую функцию — получаешь чистую. Компилятор по-прежнему все контролирует, а код засирать не обязательно.
Re[12]: Ввод-вывод и чистые функции
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 31.01.17 07:45
Оценка: 2 (1)
Здравствуйте, AlexRK, Вы писали:

_>>Она грязная с точки зрения отсутствия соответствующих атрибутов. Но сама то по построению очевидно чистая. Так что соответственно если передать в неё чистые аргументы, то и вся конструкция окажется чистой (опять же по построению, а не атрибутам типа).


ARK>Верно. Но мы таким образом теряем возможность рассуждать о свойствах программы, глядя в ее код. Видим где-то в середине шаблонного кода вызов map, но чистый он или нет — понять нельзя. Собственно, откуда мы вообще знаем, что map "чистый по построению"? Только посмотрев в исходники (а если их нет?). И если завтра Брайту взбредет в голову сунуть в map чтение файла, мы этого никак не заметим и компилятор нам ничего не скажет.


Скажет. Если ты свою ф-ю описал как pure и вызываешь чужую вроде map, то компилятор убедится, что та чужая тоже чистая. Если Брайт вставит в map нечистоты, твоя ф-я, которая ее вызывает, не скомпилируется. map и другие ФВП в D не грязные, они с автоматическим выводом чистоты.
Re[13]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 31.01.17 07:51
Оценка:
Здравствуйте, D. Mon, Вы писали:

ARK>>Верно. Но мы таким образом теряем возможность рассуждать о свойствах программы, глядя в ее код. Видим где-то в середине шаблонного кода вызов map, но чистый он или нет — понять нельзя. Собственно, откуда мы вообще знаем, что map "чистый по построению"? Только посмотрев в исходники (а если их нет?). И если завтра Брайту взбредет в голову сунуть в map чтение файла, мы этого никак не заметим и компилятор нам ничего не скажет.


DM>Скажет. Если ты свою ф-ю описал как pure и вызываешь чужую вроде map, то компилятор убедится, что та чужая тоже чистая.


"Своя" — это та, которая вызывает map, или та, которая передается в map параметром?

DM>Если Брайт вставит в map нечистоты, твоя ф-я, которая ее вызывает, не скомпилируется.


А если "ф-я, которая ее вызывает", не объявлена как pure? То всё, на неожиданные нечистоты реакции компилятора не будет?
Re[16]: Ввод-вывод и чистые функции
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 31.01.17 07:55
Оценка:
Здравствуйте, novitk, Вы писали:

N>От меня ускользает смысл. ТС вроде за аннотацию, ты вроде тоже. 99% в D это обычные грязные функции без аннотации и написать на нем чистую функцию реально нельзя, так как комбинаторы тянут грязь. То есть по факту pure в нем не додумана и не используется.


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

N>>>И два map-a это не решение проблемы, потому что потом нужно два fold-а и вообще всего в std.algorithm или как оно там называется,


Не нужно. Чистота там выводится автоматически.

N>Как мне g переделать в грязную? Я надеюсь какой-то лифтинг все же есть и мне не надо переписывать g еще раз.


int f(int i) pure {
    return i*i;
}
int h(int i) {
    writeln("Bad");
    return i*i;
}

int g(alias func)() { // автоматически чистая или грязная в зависимости от func
    return func(10);
}

int makeSureWeReStillPure() pure {
    return g!f + 1;
}

void main(string[ ] args)
{
    writeln(g!f); 
    writeln(g!h); 
    writeln(makeSureWeReStillPure());
}

100
Bad
100
101
Отредактировано 31.01.2017 7:59 D. Mon . Предыдущая версия .
Re[14]: Ввод-вывод и чистые функции
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 31.01.17 08:01
Оценка:
Здравствуйте, AlexRK, Вы писали:

DM>>Скажет. Если ты свою ф-ю описал как pure и вызываешь чужую вроде map, то компилятор убедится, что та чужая тоже чистая.


ARK>"Своя" — это та, которая вызывает map, или та, которая передается в map параметром?


Которая вызывает.

DM>>Если Брайт вставит в map нечистоты, твоя ф-я, которая ее вызывает, не скомпилируется.


ARK>А если "ф-я, которая ее вызывает", не объявлена как pure? То всё, на неожиданные нечистоты реакции компилятора не будет?


Если вызывающая не объявлена pure, значит ты от кода чистоты не требуешь явно, значит разрешаешь грязный код. Какая реакция компилятора тут нужна?
Re[15]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 31.01.17 08:09
Оценка:
Здравствуйте, D. Mon, Вы писали:

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


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

Насчет реакции компилятора согласен, в данном случае наверное никакой быть не может.
Re[16]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 31.01.17 08:35
Оценка:
Здравствуйте, novitk, Вы писали:

_>>Не, я согласен что явная аннотация важна.

_>>1. Это никак формально не гарантируется компилятором (а вот в D это добавили)
_>>2. Факт данной чистоты никак потом на практике не используется (в том числе и в D, причём скорее вследствие отсутствия соответствующих навыков у прикладных программистов).
N>От меня ускользает смысл. ТС вроде за аннотацию, ты вроде тоже. 99% в D это обычные грязные функции без аннотации и написать на нем чистую функцию реально нельзя, так как комбинаторы тянут грязь. То есть по факту pure в нем не додумана и не используется.

Ситуация на самом деле очень простая: язык предоставляет все условия для построение внутри приложения определённой части с гарантированной (компилятором) чистотой, но большинство программистов (т.к. это в основном перешедшие из мира C++ люди) игнорируют данную возможность в своей работе. Соответственно это направление не особо развивается.

Что касается "99% в D это обычные грязные функции без аннотации", то я уже писал выше, что это не верно. В D общепринятой практикой является развитое МП, так что большинство функций — это "не просто функции" и их аргументы — это не просто обычные типизированные параметры.

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

N>>>И два map-a это не решение проблемы, потому что потом нужно два fold-а и вообще всего в std.algorithm или как оно там называется,

_>>Ну как бы вообще говоря решение. Только совсем не изящное.
N>
N>int f(int i) pure {
N>    return i*i;
N>}
N>int h(int i) {
N>    writeln("Bad");
N>    return i*i;
N>}
N>int g(int function(int) pure func) pure {
N>    return func(10);
N>}
N>void main(string[ ] args)
N>{
N>   writeln(g(&f)); //no prob
N>   writeln(g(&h)); //???
N>}
N>

N>main.d(18): Error: function main.g (int function(int) pure func) is not callable using argument types (int function(int i))
N>Как мне g переделать в грязную? Я надеюсь какой-то лифтинг все же есть и мне не надо переписывать g еще раз.

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

_>>В D заложена потенциальная возможность этого. Но на практике (в библиотеках, в прикладном коде) она почти не используется.

N>Если функционал не используется, то в нем нет смысла. Пока есть сильное подозрение что авторы этой фичи в D просто не додумкали и/или не разобрались с матаном.

Нет, в язык всё введено нормально. Разве что стоит добавить одну мелочь (про которую я писал выше, с автоматической расстановкой атрибута), но и так пока можно пользоваться. Проблема именно в практике использования данной возможности. Создание библиотек заточенных на это и т.п.
Re[16]: Ввод-вывод и чистые функции
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 31.01.17 08:35
Оценка: 3 (1) +1
Здравствуйте, AlexRK, Вы писали:

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


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


Можно локально посреди грязной ф-ии для кусочка кода потребовать чистоты. Пишешь
() pure {
  x = xs.map!f.filter!g.reduce!h;  // можно, пока все чистое
  y = x + f(42); 
  // writeln("io"); // а вот этого компилятор не даст!
} ();

Корявенько, но можно.

ARK>Но, поскольку map явно не объявлен как pure, то я должен ожидать от него чего угодно.


Ну да, это ж не хаскель, раз у нас дефолт это грязные ф-ии, то любое отличие от дефолта надо требовать явно. Можно в одном месте программы проверить, что вызов map с чистым аргументом все еще чист. Тогда если реализация map станет грязной, программа не скомпилится.
Re[5]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 31.01.17 08:39
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Тут какой-то ерунды наговорили. В D map это не функция, это шаблон функции, генерик. Для шаблонов всегда работает автоматический вывод атрибутов, в том числе чистоты. Если в map передать чистую функцию, получится чистая функция. Если передать грязную — получится грязная.


Тут обсуждается немного другое. Не просто возможность "передать" чистоту дальше, а возможность изменения поведения функции (допустим применения каких-то более эффективных алгоритмов) в случае передачи чистого параметра и т.п. Я уже отвечал тут людям, что все возможности для этого есть (т.к. доступ к атрибутам передаваемого типа имеется). Но вот никаких практических реализации данной возможности я не припомню.
Re[17]: Ввод-вывод и чистые функции
От: AlexRK  
Дата: 31.01.17 08:41
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Можно локально посреди грязной ф-ии для кусочка кода потребовать чистоты. Пишешь


Ха-ха, забавно. Вообще D прикольный язычок, я смотрю.
Re[13]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 31.01.17 08:50
Оценка:
Здравствуйте, D. Mon, Вы писали:

ARK>>Верно. Но мы таким образом теряем возможность рассуждать о свойствах программы, глядя в ее код. Видим где-то в середине шаблонного кода вызов map, но чистый он или нет — понять нельзя. Собственно, откуда мы вообще знаем, что map "чистый по построению"? Только посмотрев в исходники (а если их нет?). И если завтра Брайту взбредет в голову сунуть в map чтение файла, мы этого никак не заметим и компилятор нам ничего не скажет.

DM>Скажет. Если ты свою ф-ю описал как pure и вызываешь чужую вроде map, то компилятор убедится, что та чужая тоже чистая. Если Брайт вставит в map нечистоты, твоя ф-я, которая ее вызывает, не скомпилируется. map и другие ФВП в D не грязные, они с автоматическим выводом чистоты.

К сожалению последнее работает не для всего. Простейший пример:

auto f(int x) {return x*2;}

writeln(__traits(getFunctionAttributes, f)); //pure нет
writeln(__traits(getFunctionAttributes, function (int x)=>x*2)); //pure есть


Кстати, как раз поэтому твой пример (https://dpaste.dzfl.pl/42460904b633) работает. Если заменить там "x => x*2" на подобную f, то уже не скомпилируется. Хотя по смыслу ничего не поменяется. Вот эту недоработку в работе компилятора я бы всё же поправил.
Re[8]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 31.01.17 08:57
Оценка:
Здравствуйте, D. Mon, Вы писали:

_>>Другое дело (и это справедливо отмечено в заданном на SO вопросе), что реализации алгоритмов из стандартной библиотеки в данный момент ни сами не отмечены как pure, ни требуют этого от передаваемых в них функций. Правильно это или нет — это другой вопрос, зависящий на мой взгляд от того, какого больше стиля придерживается усреднённый программист на D. Но в любом случае у желающего есть все возможности сделать любой вариант. Ну и да, наверное в идеале в будущем иметь в стандартной библиотеке все возможные реализации. )

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

Если мы хотим какую-то пользу от всего этого, то как раз "засирать код" (плодить новые версии стандартных функций) надо. Например иметь вариант функций с мемоизацией и т.п.
Re[16]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 31.01.17 09:09
Оценка:
Здравствуйте, AlexRK, Вы писали:

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

ARK>Ну, я не требую от всего кода функции чистоты, но хочу быть при этом уверенным, что map не будет писать в файлы, даже несмотря на то, что вызывается из глязной функции.
ARK>Но, поскольку map явно не объявлен как pure, то я должен ожидать от него чего угодно.

На уровне документации кода — да.

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


А вот на уровне компилятора это решается просто:
static assert ([__traits(getFunctionAttributes, my_func)[]].canFind("pure"), "Impure!");
Re[14]: Ввод-вывод и чистые функции
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 31.01.17 10:38
Оценка:
Здравствуйте, alex_public, Вы писали:

DM>>Скажет. Если ты свою ф-ю описал как pure и вызываешь чужую вроде map, то компилятор убедится, что та чужая тоже чистая. Если Брайт вставит в map нечистоты, твоя ф-я, которая ее вызывает, не скомпилируется. map и другие ФВП в D не грязные, они с автоматическим выводом чистоты.


_>К сожалению последнее работает не для всего.


Автоматический вывод работает только на шаблонных ф-ях. Но в стандартной библиотеке (и не только) ФВП как раз такие. И свои ФВП стоит в том же стиле писать, тогда все будет выводиться, а заодно и инлайниться.
Re[5]: Ввод-вывод и чистые функции
От: Nick Linker Россия lj://_lcr_
Дата: 31.01.17 10:54
Оценка:
alex_public,

_>Никто не запрещает, в том то и вся прелесть (в сравнение с Хаскелем). В тоже время у тебя в языке есть все механизмы для введения подобного запрета при желание (делается в одну короткую строчку). Т.е. язык даёт тебя полную свободу и плюс все необходимые инструменты для построения любого варианта.


То есть ты считаешь, что запреты — это плохо и это ограничивают наш полёт мысли, правильно? И чем меньше ограничений, тем выше полёт мысли?

_>Это всё следствия более общего вопроса в построение языка: мультипарадигменный он или нет. Современные удобные языки легко позволяют писать и в ООП стиле и ФП стиле и даже закопаться в МП. А можно смешать это всё в одном проекте и всё равно всё будет удобно. Именно поэтому у языка D (сильно мультипарадигменного) есть хоть какие-то шансы на большой успех (там уже больше от "политики" зависит), а у того же однопарадигменного Хаскеля таких шансов не было от рождения.


Проблема с походом Haskell в массы не в том, что он "однопарадигменный", а в том что он сложный — сложность Хаскеля не в монадах (это просто непривычная для императивщиков концепция), а в сильно продвинутых типах, которых нигде кроме экспериментальных языков нет (пример: Type-level insertion sort).
Потому в продакшене Хаскель звёзд с неба не хватает, но кое-какие применения имеет: https://github.com/commercialhaskell/commercialhaskell/blob/master/README.md

А мультипарадигменность из коробки с одной стороны позволяет программисту Васе в D писать как на фортране или Пете — как на джаве, а с другой стороны выходит боком в долгосрочной преспективе — примеров тому предостаточно.
Когда в языке из коробки нет, например, наследования и обработки исключений — это сразу делает язык гораздо проще для реализации и для изучения. И соотвественно шансы стать массовым увеличиваются.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[15]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 31.01.17 11:06
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>>>Скажет. Если ты свою ф-ю описал как pure и вызываешь чужую вроде map, то компилятор убедится, что та чужая тоже чистая. Если Брайт вставит в map нечистоты, твоя ф-я, которая ее вызывает, не скомпилируется. map и другие ФВП в D не грязные, они с автоматическим выводом чистоты.

_>>К сожалению последнее работает не для всего.
DM>Автоматический вывод работает только на шаблонных ф-ях. Но в стандартной библиотеке (и не только) ФВП как раз такие. И свои ФВП стоит в том же стиле писать, тогда все будет выводиться, а заодно и инлайниться.

Я не много не про это. Я про то, что для лямбд атрибут чистоты автоматически проставляется компилятором (и поэтому твой пример с "map!(x => x*2)" работал), а для обычных функций это почему-то не реализовано. Так что даже если я написал реально чистую функцию f, но забыл (или как большинство императивных программистов просто не в курсе про данный атрибут) проставить ей атрибут pure, то твой пример с map!(f) уже не будет работать.
Re[16]: Ввод-вывод и чистые функции
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 31.01.17 11:31
Оценка:
Здравствуйте, alex_public, Вы писали:

DM>>Автоматический вывод работает только на шаблонных ф-ях. Но в стандартной библиотеке (и не только) ФВП как раз такие. И свои ФВП стоит в том же стиле писать, тогда все будет выводиться, а заодно и инлайниться.


_>Я не много не про это. Я про то, что для лямбд атрибут чистоты автоматически проставляется компилятором (и поэтому твой пример с "map!(x => x*2)" работал), а для обычных функций это почему-то не реализовано. Так что даже если я написал реально чистую функцию f, но забыл (или как большинство императивных программистов просто не в курсе про данный атрибут) проставить ей атрибут pure, то твой пример с map!(f) уже не будет работать.


Как раз про это. Потому что упомянутая лямбда — это шаблонная ф-я тоже, вот для нее и выводится. Замени ее нешаблонной ф-ей, перестанет выводиться.
Re[6]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 31.01.17 13:12
Оценка:
Здравствуйте, Nick Linker, Вы писали:

_>>Никто не запрещает, в том то и вся прелесть (в сравнение с Хаскелем). В тоже время у тебя в языке есть все механизмы для введения подобного запрета при желание (делается в одну короткую строчку). Т.е. язык даёт тебя полную свободу и плюс все необходимые инструменты для построения любого варианта.

NL>То есть ты считаешь, что запреты — это плохо и это ограничивают наш полёт мысли, правильно? И чем меньше ограничений, тем выше полёт мысли?

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

_>>Это всё следствия более общего вопроса в построение языка: мультипарадигменный он или нет. Современные удобные языки легко позволяют писать и в ООП стиле и ФП стиле и даже закопаться в МП. А можно смешать это всё в одном проекте и всё равно всё будет удобно. Именно поэтому у языка D (сильно мультипарадигменного) есть хоть какие-то шансы на большой успех (там уже больше от "политики" зависит), а у того же однопарадигменного Хаскеля таких шансов не было от рождения.

NL>Проблема с походом Haskell в массы не в том, что он "однопарадигменный", а в том что он сложный — сложность Хаскеля не в монадах (это просто непривычная для императивщиков концепция), а в сильно продвинутых типах, которых нигде кроме экспериментальных языков нет (пример: Type-level insertion sort).
NL>Потому в продакшене Хаскель звёзд с неба не хватает, но кое-какие применения имеет: https://github.com/commercialhaskell/commercialhaskell/blob/master/README.md

Да ничего в нём нет сложного. Просто неудобен он почти для всех применений. За исключением разве что написания каких-нибудь консольных утилит анализа/трансформации файлов и т.п. приложений.

NL>А мультипарадигменность из коробки с одной стороны позволяет программисту Васе в D писать как на фортране или Пете — как на джаве, а с другой стороны выходит боком в долгосрочной преспективе — примеров тому предостаточно.


В долгосрочной перспективе всё очень хорошо видно здесь: http://www.tiobe.com/tiobe-index/ )))

NL>Когда в языке из коробки нет, например, наследования и обработки исключений — это сразу делает язык гораздо проще для реализации и для изучения. И соотвественно шансы стать массовым увеличиваются.


Это речь про Go? )))
Re[17]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 31.01.17 13:15
Оценка:
Здравствуйте, D. Mon, Вы писали:

_>>Я не много не про это. Я про то, что для лямбд атрибут чистоты автоматически проставляется компилятором (и поэтому твой пример с "map!(x => x*2)" работал), а для обычных функций это почему-то не реализовано. Так что даже если я написал реально чистую функцию f, но забыл (или как большинство императивных программистов просто не в курсе про данный атрибут) проставить ей атрибут pure, то твой пример с map!(f) уже не будет работать.

DM>Как раз про это. Потому что упомянутая лямбда — это шаблонная ф-я тоже, вот для нее и выводится. Замени ее нешаблонной ф-ей, перестанет выводиться.

А где ты видишь тут шаблонную функцию:
writeln(__traits(getFunctionAttributes, function (int x)=>x*2)); //pure есть


Ну и в любом случае, не в этом суть, а в том что для обычных функций оно не работает. А надо чтобы работало для всех (чей исходный код доступен).
Re[17]: Ввод-вывод и чистые функции
От: novitk США  
Дата: 31.01.17 14:05
Оценка:
Здравствуйте, D. Mon, Вы писали:

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

Я не знаю D. Было сообщения что комбинаторы в std.algorithm не имеют pure, что я понял как грязь. Если они сделаны через MP, то это меняет дело.

N>>Как мне g переделать в грязную? Я надеюсь какой-то лифтинг все же есть и мне не надо переписывать g еще раз.

DM>[ccode]
DM>int g(alias func)() { // автоматически чистая или грязная в зависимости от func
DM> return func(10);
DM>}
DM>[/code]
А типизацию в параметр можно вернуть? Иначе как я вообще пойму в сложной HOF, какая сигнатура должна быть у func?
Re[18]: Ввод-вывод и чистые функции
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 31.01.17 15:22
Оценка:
Здравствуйте, novitk, Вы писали:

N>А типизацию в параметр можно вернуть? Иначе как я вообще пойму в сложной HOF, какая сигнатура должна быть у func?


Да, можно вернуть, только с другим синтаксисом — через статическую интроспекцию.
int g(alias func)() 
if (isCallable!func && is(ReturnType!func==int) && Parameters!func.length==1 && is(Parameters!func[0]==int)) { 
    return func(10);
}

Сюда же можно кое-какие проверки на поведение func вставить, а также кастомные сообщения об ошибках.
Выходит громоздко, может быть можно как-то проще.
Re[19]: Ввод-вывод и чистые функции
От: novitk США  
Дата: 31.01.17 16:09
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Сюда же можно кое-какие проверки на поведение func вставить, а также кастомные сообщения об ошибках.

IMXO Микроскопом тут забивают гвоздь, выглядит приемлемо только для людей ничего не видевших кроме МП в C++.

DM>Выходит громоздко, может быть можно как-то проще.

Возник вопрос на который не могу сходу ответить. Почему бы не сделать неявный каст в грязь, если хотя бы один из параметров чистой HOF грязный, тo есть просто разрешить выражение "pureHOF(&dirtyFunc)" в грязной функции? Это в принципе соответствует моему пожеланию о автолифтинге. Замыкания/лямбды полученные таким образом, через карринг или еще как, тоже конечно грязные. Какие тут проблемы?
Re[20]: Ввод-вывод и чистые функции
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 31.01.17 16:20
Оценка:
Здравствуйте, novitk, Вы писали:

N>Возник вопрос на который не могу сходу ответить. Почему бы не сделать неявный каст в грязь, если хотя бы один из параметров чистой HOF грязный, тo есть просто разрешить выражение "pureHOF(&dirtyFunc)" в грязной функции?


Т.е. у функции на лбу в сигнатуре будет написано, что она чистая, но вот в этом месте она окажется грязной. Нафиг тогда вообще на ней что-то писать? Сейчас, когда ФВП делаются с шаблонными параметрами, все и так получается автоматически: передал ей грязную ф-ю, получил грязную, передал чистую — получил чистую. Не нужны никакие касты.
Re[7]: Ввод-вывод и чистые функции
От: Nick Linker Россия lj://_lcr_
Дата: 31.01.17 16:57
Оценка:
alex_public,

NL>>То есть ты считаешь, что запреты — это плохо и это ограничивают наш полёт мысли, правильно? И чем меньше ограничений, тем выше полёт мысли?


_>Если мы говорим про язык, то безусловно. Язык должен предоставлять мне инструменты, с помощью которых я будут устанавливать нужные мне в данном проекте запреты. А не устанавливать их сам за меня, причём некие неудобные универсальные.


Звучит как coding standard принятый в рамках проекта.

_>Да ничего в нём (Haskell) нет сложного. Просто неудобен он почти для всех применений. За исключением разве что написания каких-нибудь консольных утилит анализа/трансформации файлов и т.п. приложений.


Звучит как заблуждение.

NL>>А мультипарадигменность из коробки с одной стороны позволяет программисту Васе в D писать как на фортране или Пете — как на джаве, а с другой стороны выходит боком в долгосрочной преспективе — примеров тому предостаточно.


_>В долгосрочной перспективе всё очень хорошо видно здесь: http://www.tiobe.com/tiobe-index/ )))


Там дельфи и бейсик в топах. И ещё недавно выкопанный зомби по имени Dart. Ещё Perl почти наравне с Javascript. Ты серьёзно?

NL>>Когда в языке из коробки нет, например, наследования и обработки исключений — это сразу делает язык гораздо проще для реализации и для изучения. И соотвественно шансы стать массовым увеличиваются.


_>Это речь про Go? )))


Да, Go. И если вспомнить языки просто без наследования (js, vba), то можно заметить, сколько граблей обойдено разом просто за счёт этого. И Бьярн тоже разделяет эту мысль.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[21]: Ввод-вывод и чистые функции
От: novitk США  
Дата: 31.01.17 19:06
Оценка:
Здравствуйте, D. Mon, Вы писали:

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

С ФВП ничего не произошло, так как она сама по себе не добавляет sideeffect-ов. Результат ее применения к грязной функции очевидно загрязняет enclosing closure.

DM>Сейчас, когда ФВП делаются с шаблонными параметрами, все и так получается автоматически: передал ей грязную ф-ю, получил грязную, передал чистую — получил чистую. Не нужны никакие касты.

Сейчас в D утинная типизации шаблонов, как в плюсах. Собственно я посмотрел https://github.com/dlang/phobos/blob/master/std/algorithm/iteration.d и там вполне себе обычная плюсовая наркота. Вот из этого "template map(fun...) if (fun.length >= 1)" и страницы кода тип fun человеком не выводится. То есть пишем/читаем доки и получаем говноошибки. Все как в плюсах. Еще и очевидно для оптимизаций сделали map двухмерных. Модульность? Нет, не слышали.

Ты только не думай что я на твои игрушки наезжаю. Сам на Скале и в коллекциях там наркоты не меньше (builder-ы и прочий бред), но типизация параметров ФВП там все же есть.
Re[8]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 31.01.17 20:33
Оценка:
Здравствуйте, Nick Linker, Вы писали:

_>>Если мы говорим про язык, то безусловно. Язык должен предоставлять мне инструменты, с помощью которых я будут устанавливать нужные мне в данном проекте запреты. А не устанавливать их сам за меня, причём некие неудобные универсальные.

NL>Звучит как coding standard принятый в рамках проекта.

coding standard к сожалению не проверяются компилятором. )

Речь немного о другом. Что в своём (нормальном мультипарадигменном) языке я могу легко добиться иммутабельного поведения любой нужной мне переменной. Но я не хочу что бы все переменные в проекте были иммутабельными. Понятна мысль? )

_>>Да ничего в нём (Haskell) нет сложного. Просто неудобен он почти для всех применений. За исключением разве что написания каких-нибудь консольных утилит анализа/трансформации файлов и т.п. приложений.

NL>Звучит как заблуждение.

Хех, на эту тему на данном форуме уже были флеймы дикой длины. Повторяться нет никакого желания. Тем более, что никаких новых аргументов за эти годы не добавилось ни с одной стороны.

_>>В долгосрочной перспективе всё очень хорошо видно здесь: http://www.tiobe.com/tiobe-index/ )))

NL>Там дельфи и бейсик в топах. И ещё недавно выкопанный зомби по имени Dart. Ещё Perl почти наравне с Javascript. Ты серьёзно?

Ну если тебя не устраивает данный рейтинг, то приведи свой, более авторитетный на твой взгляд. Посмотрим какие там места занимают мультипарадигменные языки. )

NL>Да, Go. И если вспомнить языки просто без наследования (js, vba), то можно заметить, сколько граблей обойдено разом просто за счёт этого. И Бьярн тоже разделяет эту мысль.


По поводу Go лично у меня основная претензия в другом (претензия на уровне абстрактного мнения о языке — переходить на что-то подобное у меня потребности нет в любом случае, даже если бы не было претензий). На мой вкус современный статических типизированный язык не поддерживающий парадигму обобщённого программирования (пускай даже на уровне убогих дженериков, как в Java/.Net) не имеет права на существование.
Re[9]: Ввод-вывод и чистые функции
От: Nick Linker Россия lj://_lcr_
Дата: 01.02.17 08:31
Оценка:
alex_public,

_>Речь немного о другом. Что в своём (нормальном мультипарадигменном) языке я могу легко добиться иммутабельного поведения любой нужной мне переменной. Но я не хочу что бы все переменные в проекте были иммутабельными. Понятна мысль? )


Эта мысль весьма противоречива в своей сущности:
1. С одной стороны есть теорема Райса, которая накладывает принципиальные ограничения на статический анализ
2. С другой стороны для выполнения преобразований с АСТ (например инлайнинг, фьюжн, частичное применение) компилятору необходимы консервативные предположения (как можно более полная информация о типах, чистота, иммутабельность)
3. Ты хочешь уничтожить некоторые из предположений, что поставит крест на применимости анализа и преобразований
4. Таким образом ты говоришь "эй, компилятор, я знаю как лучше, отойди в сторонку и не мешай!", и в сущности начинаешь делать его работу
5. И это язык программирования будущего.

Я правильно понял твою мысль?

_>Хех, на эту тему на данном форуме уже были флеймы дикой длины. Повторяться нет никакого желания. Тем более, что никаких новых аргументов за эти годы не добавилось ни с одной стороны.


Возможно кто-то из не учавствовавших в этих "флеймах дикой длины" теперь пишет код на Хаскеле просто на работе и видит своими глазами, что неудобство только одно — невозможно так просто "х*як-х*як и в продакшен" — компилятор сильно мешает. Так что про "консольные утилиты" — это не более чем заблуждение.
Этот аргумент был: State of the Haskell ecosystem?

_>По поводу Go лично у меня основная претензия в другом (претензия на уровне абстрактного мнения о языке — переходить на что-то подобное у меня потребности нет в любом случае, даже если бы не было претензий). На мой вкус современный статических типизированный язык не поддерживающий парадигму обобщённого программирования (пускай даже на уровне убогих дженериков, как в Java/.Net) не имеет права на существование.


Но он однако существует и похоже становится сильно популярным. Жаль, но так работает популярность — куда легче вход, туда и идут массы.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[10]: Ввод-вывод и чистые функции
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 01.02.17 12:04
Оценка: +1 :)
Здравствуйте, Nick Linker, Вы писали:

NL>4. Таким образом ты говоришь "эй, компилятор, я знаю как лучше, отойди в сторонку и не мешай!",


А лучше "эй, компилятор, иди сюда и активно мешай"?
Приседать и бегать в мешках ради удобства компилятора?
Re[11]: Ввод-вывод и чистые функции
От: Nick Linker Россия lj://_lcr_
Дата: 01.02.17 14:53
Оценка:
D. Mon,

NL>>4. Таким образом ты говоришь "эй, компилятор, я знаю как лучше, отойди в сторонку и не мешай!",


DM>А лучше "эй, компилятор, иди сюда и активно мешай"?

DM>Приседать и бегать в мешках ради удобства компилятора?

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

Хотя я думаю, большинство людей будут считать что не нужно, пока речь не будет идти об их бабушках.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Отредактировано 01.02.2017 14:56 Nick Linker . Предыдущая версия .
Re[10]: Ввод-вывод и чистые функции
От: alex_public  
Дата: 01.02.17 16:23
Оценка:
Здравствуйте, Nick Linker, Вы писали:

_>>Речь немного о другом. Что в своём (нормальном мультипарадигменном) языке я могу легко добиться иммутабельного поведения любой нужной мне переменной. Но я не хочу что бы все переменные в проекте были иммутабельными. Понятна мысль? )

NL>Эта мысль весьма противоречива в своей сущности:
NL>1. С одной стороны есть теорема Райса, которая накладывает принципиальные ограничения на статический анализ
NL>2. С другой стороны для выполнения преобразований с АСТ (например инлайнинг, фьюжн, частичное применение) компилятору необходимы консервативные предположения (как можно более полная информация о типах, чистота, иммутабельность)

Совершенно верно. И в нормальном языке мы стараемся указать компилятору максимум информации. Например мутабельная данная переменная или иммутабельная. Чистая у нас функция или нет. И т.д. и т.п. Т.е. я как раз за максимально подробную статическую типизацию из которой компилятор сможет сделать максимум выводов.

NL>3. Ты хочешь уничтожить некоторые из предположений, что поставит крест на применимости анализа и преобразований


Не уничтожить, а местами заменить другими предположениями (кстати подобное нагляднее всего можно увидеть в каком-нибудь Rust'е, где иммутабельное поведение тоже подразумевается, но есть модификатор mut для изменения поведения переменной).

NL>4. Таким образом ты говоришь "эй, компилятор, я знаю как лучше, отойди в сторонку и не мешай!", и в сущности начинаешь делать его работу


Ну так это смотря какой компилятор.

Скажем компилятору C++ уже давно перестали пытаться такое говорить (хотя когда-то пытались, всяческими указаниями на inline, ассемблерными вставками и т.п.), потому как он отлично справляется со своими задачами.

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

NL>5. И это язык программирования будущего.


Не знаю что ты называешь языком будущего. Но например за последние несколько лет одна из самых интересных на мой взгляд инноваций (именно реально чего-то нового, а не очередного воплощения идей 60-70 годов) появилась не в каком-то новом языке, а в старичке C++. Это я говорю про семантику перемещения.

_>>Хех, на эту тему на данном форуме уже были флеймы дикой длины. Повторяться нет никакого желания. Тем более, что никаких новых аргументов за эти годы не добавилось ни с одной стороны.

NL>Возможно кто-то из не учавствовавших в этих "флеймах дикой длины" теперь пишет код на Хаскеле просто на работе и видит своими глазами, что неудобство только одно — невозможно так просто "х*як-х*як и в продакшен" — компилятор сильно мешает. Так что про "консольные утилиты" — это не более чем заблуждение.
NL>Этот аргумент был: State of the Haskell ecosystem?

Хы, ожидал какой-то сомнительной ссылки с рассуждениями "Хаскель круче всех", а тут неожиданно вполне разумный анализ. Разве что слегка промелькнул известный миф о каких-то преимуществах Хаскеля для многопоточности, но это простительно. А так вполне чётко всё изложено. И при этом полностью соответствует моим словам. С оценкой "Best in class" (а я лично только такое и рассматриваю при при выборе инструмента в новой области) там находится ровно один тип ПО, который они обозвали "компиляторами". На мой взгляд это излишне узкое название, а я бы сказал что речь о любых консольных анализаторах (т.е. приложениях, которые при старте читают некие данные, потом выполняют с ними сложные преобразования и в конце выполняют вывод результата). И то это моя оценка, а некоторые местные специалисты по написанию компиляторов говорят что там некоторые самые эффективные алгоритмы парсинга "энергичны и мутабельны".

_>>По поводу Go лично у меня основная претензия в другом (претензия на уровне абстрактного мнения о языке — переходить на что-то подобное у меня потребности нет в любом случае, даже если бы не было претензий). На мой вкус современный статических типизированный язык не поддерживающий парадигму обобщённого программирования (пускай даже на уровне убогих дженериков, как в Java/.Net) не имеет права на существование.

NL>Но он однако существует и похоже становится сильно популярным. Жаль, но так работает популярность — куда легче вход, туда и идут массы.

Думаю что они всё же добавят эту возможность: https://github.com/golang/go/issues/15292 )
Re[3]: Ввод-вывод и чистые функции
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.02.17 04:58
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Ну, в языке D есть pure-функции, но при этом никаких лифтингов ни в какие монады там делать не надо.


Ди — энергичный язык. Ему на фиг не нужны монады для вовода-вывода. У него любая функция может делать ввод вывод. А чистота не более чем вычисляемый атрибут.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Ввод-вывод и чистые функции
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 02.02.17 12:15
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Ди — энергичный язык. Ему на фиг не нужны монады для вовода-вывода.


По-хорошему, энергичность еще ничего не значит. Идрис вон тоже энергичный, но ввод-вывод все равно отражен в монадоподобных типах и do-синтаксисе, просто так в чистой ф-ии строчку не выведешь.
Re[5]: Ввод-вывод и чистые функции
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.02.17 14:29
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>По-хорошему, энергичность еще ничего не значит. Идрис вон тоже энергичный, но ввод-вывод все равно отражен в монадоподобных типах и do-синтаксисе, просто так в чистой ф-ии строчку не выведешь.


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

В прочем проблемы с побочными эффектами в Хаскеле связаны не только с ленивость. Главным образом проблема в том, что в Хаскеле вычисления зависимые (не путать с зависимыми типами), а значит их порядок определяется сложным образом (не определяется последовательностью кода в функции). Зависимые вычисления могут быть энергичными. Линивость же приводит к тому, что вычисление может вовсе не быть сделано.

А просто "чистота" ровным счетом ничего не значит. Например, тот же консольный вывод данные не меняет, но побочным эффектом является. Его вполне можно использовать в энергичном языке. Даже если вычисления зависимые консольный вывод произойдет после вычисление его параметров.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Ввод-вывод и чистые функции
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 03.02.17 07:56
Оценка:
Здравствуйте, VladD2, Вы писали:

DM>>По-хорошему, энергичность еще ничего не значит. Идрис вон тоже энергичный, но ввод-вывод все равно отражен в монадоподобных типах и do-синтаксисе, просто так в чистой ф-ии строчку не выведешь.


VD>Думаю, что ты ошибешься. Я погугли и первое что попалось — это видео где орел без каких либо монад тупо вызывает printf в REPL-е передавая ему значения.


Я на Идрисе писал, представляю о чем говорю. А что за видео ты видел, можно ссылку?

PS. REPL'ы обычно уже в монаде IO или ее аналоге живут, там принты и должны работать сразу. В репле писать это не то же самое, что чистый код.
Отредактировано 04.02.2017 4:08 D. Mon . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.