Есть ли в Scala ограничение по значению, такое как ML, если нет, то почему?

Вот мои мысли по этому вопросу. Может ли кто-нибудь подтвердить, опровергнуть или уточнить?

Я написал:

Scala не объединяет ковариант List[A] с GLB ⊤, назначенным на List[Int], bcz afaics в подтипах " biunification " имеет значение направление присваивания. Таким образом, None должен иметь тип Option[⊥] (т. Е. Option[Nothing]), то же самое Nil тип List[Nothing], который не может принимать назначение от Option[Int] или List[Int] соответственно. Таким образом, проблема ограничения ценностей проистекает из безнаправленной унификации, и глобальное биобъединение считалось неразрешимым до недавнего исследования, указанного выше.

Вы можете просмотреть контекст вышеприведенного комментария.

Ограничение значения ML запрещает параметрический полиморфизм в (ранее считалось редким, но, возможно, более распространенным ) случаев, когда в противном случае это было бы разумно (то есть типобезопасно), например, особенно для частичного применения каррированных функций (что важно в функциональном программировании), потому что альтернативные решения типизации создают расслоение между функциональным и императивным программированием, а также нарушить инкапсуляцию модульных абстрактных типов. В Haskell есть аналогичное ограничение двойственной мономорфизации. OCaml в некоторых случаях смягчает ограничения. Я подробно остановился на некоторых из этих деталей.

РЕДАКТИРОВАТЬ: моя первоначальная интуиция, выраженная в приведенной выше цитате (что ограничение значения может быть устранено путем выделения подтипов) неверно. Ответы ИМО хорошо проясняют проблему (ы), и я не могу решить, какой из наборов, содержащих ответы Алексея, Андреаса или мой, должен быть лучшим ответом. ИМО, они все достойны.


person Shelby Moore III    schedule 03.02.2018    source источник


Ответы (3)


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

let r : ∀A.Ref(List(A)) = ref [] in
r := ["boo"];
head(!r) + 1

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

Следовательно, когда вы добавляете ссылки на F ‹: тогда вам нужно наложить ограничение на значение, чтобы не потерять разумность. Точно так же MLsub не может избавиться от ограничения значения. Scala уже применяет ограничение значения через свой синтаксис, поскольку нет возможности даже написать определение значения, которое имело бы полиморфный тип.

person Andreas Rossberg    schedule 03.02.2018
comment
@ShelbyMooreIII, эквивалентная вещь, которую вы не можете написать на Scala, будет val r : List[A] = Nil. Форма def id[A](x:A):A = x всегда определяет функцию, поэтому не требует дополнительных ограничений. - person Shelby Moore III; 03.02.2018
comment
Изучая пример, я согласен, что проблема не возникает из-за отсутствия подтипов, вывода или аннотаций , но исключительно потому, что привязка var r[A] : List[A] = Nil позволяет создавать экземпляр def (только один раз) вне функции, но с лексической областью видимости в параметрическом полиморфизме функции. Возможно, именно это вы имеете в виду, говоря о синтаксическом разрешении комбинации «параметрического полиморфизма с изменяемыми ссылками»? Подразумевается, что Scala не является параметрическим полиморфным? В Scala есть изменяемые ссылки, так какой из ваших критериев не соответствует Scala? - person Andreas Rossberg; 03.02.2018
comment
@ShelbyMooreIII, Scala имеет и то, и другое, и имеет синтаксическое ограничение, которое включает ограничение значения, см. Комментарий выше. - person Shelby Moore III; 03.02.2018
comment
Если в Scala я помещаю _1_ в лексическую область видимости функции, параметризованной на _2_, тогда _3_ полиморфен по отношению к. для каждой количественной оценки переменных типа этой функции, то есть каждого вызова (также известного как приложение) указанной функции из внешней лексической области видимости. Я думаю, вы хотите, чтобы _4_ (он же _5_) был полиморфным по отношению к w.r.t. для каждого приложения указанной функции, даже если она применяется во внутренней лексической области видимости? Итак, _6_ привязка - это нерелевантная деталь неявного закрытия с мемоизацией? Я теперь правильно понимаю? - person Andreas Rossberg; 03.02.2018
comment
@ShelbyMooreIII, точнее, первое не полиморфное значение, а мономорфное значение в области некоторого окружающего типа или параметра типа. С этим нет проблем, и это именно то, что приведет к ограничению ценности в ML. Я не понимаю вашего вопроса о привязках let, но замыкания и мемоизация - это семантически несущественные детали реализации. - person Shelby Moore III; 03.02.2018
comment
Ty. Я знаю, что вы эксперт, но, кстати, он так же полиморфен, как и функция (переменные типа), и я сомневаюсь, что вы станете утверждать, что параметризованная функция типа не является параметризованной полиморфной. Мономорфный кажется перегруженным термином (часто означающим специализацию реализации функции без изменения ее инвариантной формы), поэтому IMO не так информативен для непрофессионала. Вы говорите, что ограничения Scala точно такие же, но в моем первом комментарии я уже показал пример ограничения в MiltonML, которого нет в Scala. Мне интересно, знает ли кто-нибудь, какой компромисс между двумя подходами? - person Andreas Rossberg; 03.02.2018
comment
Oic, пример, который я предоставил для Scala, по своей сути выполняет расширение Eta для _1_ _2_, которое также не является Значение t ограничено в ML. Проблема заключалась в порядке оценки и запоминания _3_, в котором _4_ оценивал одно из _5_ только один раз при построении _6_. Так является ли выбор дизайна Scala таким же ограничительным, как ограничение значений в ML? Или это как раз ограничение стоимости? - person Shelby Moore III; 03.02.2018
comment
@ShelbyMooreIII, я сказал, что синтаксическое ограничение Scala включает ограничение значения, поэтому оно еще сильнее: в ML я могу определить val id: 'a -> 'a = fn x => x как полиморфное значение, но я не могу в Scala. Мономорфизм вообще не перегружен, он определяется тем, где находятся связующие / квантификаторы для переменных типа. Что-то полиморфно, когда оно имеет количественно определенный тип. К сожалению, ML обычно не делает квантификаторы явными в своем синтаксисе, а только в правилах типизации. - person Shelby Moore III; 04.02.2018
comment
Первоначальный источник моей путаницы (вызванной в значительной степени отсутствием у меня опыта работы с синтаксисом + семантикой как Scala, так и ML) по поводу отсутствия полиморфных значений в Scala был связан с тем, что я не заметил, что недоступность let l = [] является тем же ограничением, что и _2_, потому что я не осознавал неявную эквивалентность расширения Eta при использовании _3_ вместо этого в Scala. Таким образом, Scala, будучи более строгой, но более регулярной, не допускает ни одного из вышеупомянутых значений, однако ML допускает первое в некоторых, но не во всех случаях, когда это безопасно. - person Andreas Rossberg; 04.02.2018
comment
Oic, если параметр типа val r[A] : List[A] = Nil определяется количественно в месте вызова функции, val f[A] : A -> A = id(id) в теле функции является мономорфным относительно. к функции, а полиморфизм def f[A](x:A):A = id(id(x)) есть только для функции без разделения. Таким образом, специализация мономорфизации границ (ей) класса типов функции в месте вызова в специальном полиморфизме (и специализации шаблонов C ++) означает, что тело функции является мономорфным по отношению к. к полиморфизму. Экзистенциальные объекты (также известные как trait-объекты Rust) связывают границы класса типов с объектом (не функцией), поэтому динамическая диспетчеризация (полиморфизм) не может мономорфизировать функцию. - person Shelby Moore III; 04.02.2018
comment
Я полагаю, что подавляющее большинство программистов находят эти детали сбивающими с толку, поэтому я полагаю, что нам потребовалось бы упрощение концепций, чтобы довести такие PL до мейнстрима. Ограничение Scala более регулярное - это K.I.S.S. принципиальный. P.S. Я никогда не использовал ML и только вчера впервые использовал ML-ответ (т.е. я делал все это в своей голове, читая примеры / спецификации до этого). И Scala, над которой я в основном только время от времени играл, давая ответы на эти вопросы. Даже я не обновлял свой опыт работы с C ++ с 1999 года. Я пришел к этому из-за почти полного отсутствия опыта работы со Scala и ML. - person Shelby Moore III; 04.02.2018
comment
Спасибо, что помогли мне разобраться в этой проблеме. К вашему сведению, я полностью переписал мой ответ, чтобы понять, что я получил. Возможно, вы сможете проверить его на наличие ошибок, если у вас будет время и интерес. Моя проблема сейчас в том, что я не знаю, какой ответ выбрать как лучший, и сравнил достоинства трех ответов в начальной части своих ответов. Ваше здоровье. Надеюсь, наши усилия могут послужить обучающим ресурсом для читателей. - person Shelby Moore III; 04.02.2018
comment
1. но не указывает явно, что значения ограничены. Это в 3.3 Типы, не являющиеся значениями 2. т.е. подтип ⊥ и супертип в точности противоположны 3. _1_ не является предполагаемым типом, это его часть, как и _2_ не тип. - person Shelby Moore III; 04.02.2018

Все намного проще. В Scala значения не могут иметь полиморфные типы, могут только методы. Например. если вы напишете

val id = x => x

его тип не [A] A => A.

И если вы возьмете полиморфный метод, например

 def id[A](x: A): A = x

и попробуйте присвоить ему значение

 val id1 = id

снова компилятор попытается (и в этом случае не удастся) вывести конкретное A вместо создания полиморфного значения.

Так что проблемы не возникает.

РЕДАКТИРОВАТЬ:

Если вы попытаетесь воспроизвести пример http://mlton.org/ValueRestriction#_alternatives_to_the_value_restriction в Scala, проблема, с которой вы сталкиваетесь, заключается не в отсутствии let: val ей прекрасно соответствует. Но вам понадобится что-то вроде

val f[A]: A => A = {
  var r: Option[A] = None
  { x => ... }
}

что незаконно. Если вы пишете def f[A]: A => A = ..., это допустимо, но при каждом вызове создается новый r. В терминах машинного обучения это выглядело бы как

val f: unit -> ('a -> 'a) =
    fn () =>
       let
          val r: 'a option ref = ref NONE
       in
          fn x =>
          let
             val y = !r
             val () = r := SOME x
          in
             case y of
                NONE => x
              | SOME y => y
          end
       end

val _ = f () 13
val _ = f () "foo"

что разрешено ограничением стоимости.

То есть правила Scala эквивалентны разрешению только лямбда-выражений в качестве полиморфных значений в ML вместо всего, что позволяет ограничение значений.

person Alexey Romanov    schedule 03.02.2018
comment
Также есть версии ML с подтипами, например lambda-the-ultimate.org/node/5393. Это не влияет на полиморфные значения: поскольку правила типизации для MLsub - это просто правила типизации для ML с дополнительным (SUB) правилом, любое выражение, набираемое в ML, можно тривиально ввести в MLsub с тем же типом. - person Alexey Romanov; 03.02.2018
comment
Если вы написали «с точностью до наоборот», вы указали на опечатку, в которой я переставил ⊥ и ⊤. Но это исправление не отменяет моего утверждения «не может быть заполнено». Когда я отвечал ранее, я подумал, что вы могли иметь в виду тип _1_, имеющий направление ограничений ковариации, противоположное направлению _2_. Только что заметил опечатку. Спасибо. Тем не менее, как я объяснил выше в сочетании с моим ответом, невозможно создать значение с типом _3_, чтобы тип _4_ был _5_. Как вы подразумевали, этот тип имеет смысл только в контексте функции. - person Alexey Romanov; 03.02.2018
comment
Тип ML List[A] не является типом полиморфного значения A, а тип List[A] is A мне кажется ошибкой категории: даже не ошибкой. [A >: Nothing <: Any] и _6_ - это переменные типа, а не выражения, у них нет типов. - person Shelby Moore III; 03.02.2018
comment
'a list ref - это тип (схема) полиморфного значения 'a. - person Alexey Romanov; 03.02.2018
comment
Я добавил объяснение, как этот пример будет работать в Scala, и более прямое сравнение между ограничением Scala без полиморфных значений и ограничением значений. - person Alexey Romanov; 03.02.2018
comment
Добавленный вами пример нового экземпляра ссылки _1_, созданного для каждой количественной оценки переменной типа _2_, устраняет проблему безопасности типов как в Scala, так и в ML. Функция ML (недоступно в Scala) объявляет ссылочный тип, который, как (повторно) количественно определяемый его лексической областью видимости даже из-за повторных приложений изнутри указанной области, не создает новых экземпляров, если порядок оценки конструкции _3_ находится за пределами указанного повторного приложения через for пример привязки _4_. - person Alexey Romanov; 03.02.2018
comment
Первоначальный источник моей путаницы (вызванной в значительной степени отсутствием у меня опыта работы с синтаксисом + семантикой как Scala, так и ML) по поводу отсутствия полиморфных значений в Scala был связан с тем, что я не заметил, что недоступность val r[A] : List[A] является тем же ограничением, что и ∀A.List[A], потому что я не осознавал неявную эквивалентность расширения Eta при использовании val r : List[A] вместо этого в Scala. Таким образом, Scala, будучи более строгой, но более регулярной, не допускает ни одного из вышеупомянутых значений, однако ML допускает первое в некоторых, но не во всех случаях, когда это безопасно. - person Shelby Moore III; 04.02.2018
comment
Спасибо, что помогли мне разобраться в этой проблеме. К вашему сведению, я полностью переписал мой ответ, чтобы понять, что я получил. Возможно, вы сможете проверить его на наличие ошибок, если у вас будет время и интерес. Моя проблема сейчас в том, что я не знаю, какой ответ выбрать как лучший, и сравнил достоинства трех ответов в начальной части своих ответов. Ваше здоровье. Надеюсь, наши усилия могут послужить учебным ресурсом для читателей. - person Shelby Moore III; 04.02.2018
comment
@AluanHaddad, предоставляющий ограничение значений в стиле ML, не является желательной функцией. Ограничение значения является нежелательным ограничением. Итак, «предоставлять» - неправильный глагол. Я ценю ваш комментарий, потому что мне, вероятно, следовало пояснить, что такое ограничение значения ML и что это нежелательное ограничение языка. Может подредактирую вопрос. Кроме того, до недавнего времени я мало знал об ограничении ценностей и, возможно, до сих пор ничего не знаю. :-) - person Shelby Moore III; 04.02.2018

РЕДАКТИРОВАТЬ: этот ответ был неверно до. Я полностью переписал приведенное ниже объяснение, чтобы получить свое новое понимание из комментариев под ответами Андреаса и Алексея.

История редактирования и история архивов этой страницы на archive.is содержат запись моего предыдущего недоразумения и обсуждения. Еще одна причина, по которой я решил отредактировать, а не удалить и написать новый ответ, - это сохранить комментарии к этому ответу. ИМО, этот ответ по-прежнему необходим, потому что, хотя Алексей отвечает на заголовок темы правильно и кратко - также разработка Андреаса была для меня наиболее полезной для понимания - все же я думаю, что непрофессиональному читателю может потребоваться другой, более целостный (но, надеюсь, все же генеративная сущность) объяснение, чтобы быстро получить некоторую глубину понимания проблемы. Также я думаю, что другие ответы неясны, насколько запутанным является целостное объяснение, и я хочу, чтобы у наивных читателей была возможность попробовать его на вкус. Предыдущие разъяснения, которые я нашел, не содержат всех деталей на английском языке, а вместо этого (как математики обычно делают для повышения эффективности) полагаются на читателя, чтобы различить детали из нюансов примеров символического языка программирования и необходимых знаний предметной области ( например, общие сведения о дизайне языков программирования).


Ограничение значения возникает, когда у нас есть изменение ссылочных 1 параметризованных объектов типа 2. Небезопасность типа, которая может возникнуть без ограничения значения, продемонстрирована в следующем примере кода MLton:

val r: 'a option ref = ref NONE
val r1: string option ref = r
val r2: int option ref = r
val () = r1 := SOME "foo"
val v: int = valOf (!r2)

Значение NONE (которое похоже на null), содержащееся в объекте, на который ссылается r, может быть присвоено ссылке с любым конкретным типом для параметра типа 'a, потому что r имеет полиморфный тип a'. Это сделает тип небезопасным, потому что, как показано в примере выше, тот же объект, на который ссылается r, который был назначен как для string option ref, так и для int option ref, может быть записан (т. Е. Изменен) со значением string через ссылку r1, а затем прочитан как значение int. по ссылке r2. Ограничение значения вызывает ошибку компилятора для приведенного выше примера.

Сложность ввода возникает для предотвращения 3 (повторной) количественной оценки (т.е. привязки или определения) параметра типа (также известного как переменная типа) указанной ссылки (и объекта, на который она указывает) для типа который отличается при повторном использовании экземпляра указанной ссылки, который ранее был количественно определен другим типом.

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

Кстати, их появление иногда бывает не интуитивно из-за отсутствия явный универсальный квантификатор ∀ (поскольку неявный ранг-1 предшествующий лексический количественную оценку области можно исключить из лексического порядка оценки с помощью таких конструкций, как let или сопрограммы) и, возможно, большей нерегулярности (по сравнению со Scala) того, когда могут возникнуть небезопасные случаи в ограничении значений ML:

Андреас написал :

К сожалению, ML обычно не делает квантификаторы явными в своем синтаксисе, а только в правилах типизации.

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

Scala делает синтаксическим ограничением против всего такого ссылки, что является компромиссом, ограничивающим например, тот же и даже больше случаев (которые были бы безопасны, если не ограничивать), чем ограничение значения ML, но более регулярное в том смысле, что мы не будем ломать голову над сообщение об ошибке, относящееся к ограничению значения. В Scala мы никогда не разрешал создавать такую ​​ссылку. Таким образом, в Scala мы можем только в явных случаях, когда новый экземпляр ссылки создается при количественной оценке параметров типа. Примечание. OCaml расслабляет ограничение значения в некоторых случаях.

Обратите внимание, что как Scala, так и ML не позволяют объявить ссылку неизменной 1, хотя объект, на который они указывают, можно объявить неизменяемым с помощью val. Обратите внимание, что нет необходимости вводить ограничения для ссылок, которые нельзя изменять.

Причина, по которой изменяемость ссылочного типа 1 требуется для возникновения сложных случаев типизации, заключается в том, что если мы создаем экземпляр ссылки (например, в предложении замен let) с не- параметризованный объект (т.е. не None или Nil 4, а вместо этого, например, Option[String] или List[Int]), тогда ссылка не будет иметь полиморфного типа (относящегося к объекту, на который он указывает), и поэтому проблема повторной количественной оценки никогда не возникает. Таким образом, проблемные случаи возникают из-за создания экземпляра с полиморфным объектом, а затем последующего присвоения нового количественно определенного объекта (т. Е. Изменения ссылочного типа) в повторно количественно определенном контексте с последующим разыменованием (чтением) из (объект, на который указывает) ссылка в последующем повторно количественный контекст. Как упоминалось выше, когда повторно квантифицированные параметры типа конфликтуют, возникают сложности с типизацией, и небезопасные случаи должны быть предотвращены / ограничены.

Фух! Если вы поняли это, не просматривая связанные примеры, я впечатлен.

1 ИМО, чтобы вместо этого использовать фразу «изменяемые ссылки» вместо «изменчивость ссылочного объекта» и «изменчивость ссылочного типа» было бы более потенциально запутанным, потому что наше намерение состоит в том, чтобы изменить значение объекта (и его тип), на которое ссылается указатель, - не относящиеся к изменчивости указателя того, на что указывает ссылка. Некоторые языки программирования даже не различают явно, когда они запрещают, в случае примитивные типы: выбор изменения ссылки или объекта, на который они указывают.


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

3 Чтобы предотвратить ошибку сегментации во время выполнения из-за доступа (чтения или записи) к указанному объекту с предположением о его статически (то есть во время компиляции) определенном типе, который не является типом что объект действительно имеет.

4 Какие NONE и [] соответственно в ML.

Извините за аргумент, но синтаксис Scala не мешает мне писать val r: 'a option ref = ref NONE val r1: string option ref = r val r2: int option ref = r val () = r1 := SOME "foo" val v: int = valOf (!r2) , а скорее проверщик типов жалуется, что «не найдено: тип A». Тем не менее, Scala не применяет другие ограничения значений, которые можно увидеть в ML, как, например, когда я успешно скомпилировал в REPL NONE null.

person Shelby Moore III    schedule 03.02.2018
comment
Показывает, насколько я знаю ... Вот что сбивает мои программы на F #! Спасибо за это. Я узнал кое-что интересное. - person Shelby Moore III; 03.02.2018
comment
@AluanHaddad, я добавил к вопросу краткое изложение об ограничении значений. - person Aluan Haddad; 03.02.2018
comment
Отлично, читаю :) Интересное обсуждение и на GitHub. Некоторые из них кажутся мне непонятными, но вы много говорили о закрытии. Лично я считаю, что это самая эффективная форма инкапсуляции. - person Shelby Moore III; 03.02.2018
comment
Существует вероятность многих ошибок и упущений. Экспертная оценка приветствуется. Я не специалист, а скорее подстрекатель или агитатор. :-) Ваше здоровье. - person Aluan Haddad; 03.02.2018
comment
Несколько языков недавно получили предложения, которые сделают замыкания менее удобными с синтаксической точки зрения. Например, списки захвата, предлагаемые для C #, и Spores, предлагаемые для Scala. Я думаю, они не попадают в цель, потому что, если функция имеет непустую среду закрытия, это потому, что логика должна ссылаться на эту среду. Усложнение синтаксиса не помогает, потому что вам все равно придется переписать свою функцию на функцию с другой семантикой, потому что если вы что-то захватили, это произошло потому, что вы это использовали. - person Shelby Moore III; 03.02.2018
comment
@AluanHaddad Я полностью переписал свой ответ, потому что он был неправильным. Если у вас есть время и интерес, мне интересно узнать, поможет ли это новое объяснение вам глубже понять проблему ограничения ценности? Я считаю, что объяснять проблему целостным довольно сложно, независимо от того, как я это формулирую. - person Aluan Haddad; 03.02.2018
comment
Ограничение значения - это компромисс ML для предотвращения всех небезопасных случаев, а также предотвращения некоторых (, которые ранее считались редкими) безопасные случаи, чтобы упростить систему типов. Ограничение значения считается лучшим компромиссом, поскольку ранний (устаревший?) опыт работы с более сложные подходы к вводу текста, которые не ограничивали ни одного или такого количества безопасных случаев, вызвали бифуркацию между императивным и чистое функциональное (также известное как аппликативное) программирование и просочилась часть инкапсуляции абстрактных типов в функциональные модули ML. Я процитировал некоторые источники и подробно изложил здесь. Тем не менее, интересно, что я размышляю, действительно ли ранний аргумент против раздвоения действительно противоречит тому факту, что ограничение ценности совсем не требуется для вызова по имени (например, ленивое вычисление в стиле Haskell, когда оно также запоминается по необходимости), потому что концептуально частичные приложения не формируют замыкания для уже оцененного состояния; и для модульных композиционное обоснование, а в сочетании с чистотой - модульное ( теория категорий и эквациональное рассуждение) контроль и композиция эффектов. Ограничение мономорфизации аргумент против вызова по имени: действительно о принудительном использовании аннотаций типов, но явное указание, когда требуется оптимальная мемоизация (также известная как совместное использование), возможно, менее обременительно, учитывая, что указанная аннотация необходима для модульности и читабельности так или иначе. Вызов по значению - это тонкий уровень управления, поэтому там, где нам нужен этот низкоуровневый элемент управления, возможно, нам следует принять ограничение по значению, потому что редкие случаи, которые допускает более сложная типизация, будут менее полезны в императивная и аппликативная настройки. Однако я не знаю, можно ли их расслоить / разделить на одном языке программирования гладким / элегантным образом. Алгебраические эффекты могут быть реализованы на языке CBV, таком как ML, и они могут обойти ограничение значения. IOW, если ограничение значения влияет на ваш код, возможно, это потому, что ваш язык программирования а в библиотеках отсутствует подходящая метамодель для обработки эффектов. - person Shelby Moore III; 04.02.2018