1-freelance.ru

Журнал "Фрилансер"
2 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Запутался в возвращаемом значении функции

Запутался в возвращаемом значении функции

Эта функция предназначена для вычисления факториала целого числа. В ветви x>1 нет возвращаемого значения для функции Fun . Поэтому эта функция не должна возвращать правильный ответ.

Но когда fun(4) или некоторые другие примеры проверяются, правильные ответы получаются неожиданно. Почему?

Код assembly этой функции (call Fun(4)):

Может быть, это и есть причина : значение sum сохраняется в регистре eax , а возвращаемое значение также сохраняется в eax , поэтому Fun возвращает правильный результат.

6 ответов

  • запутался в nodeJS

Я не знаю , есть ли у этого вопроса правильное место в SO , если не сказать m, я его передвину. Я привык к Rails , и меня интересует nodeJS , и я хотел бы понять, что означают non blocking связи. Означает ли это, что существует постоянное соединение с database ? (явно ли socket.io обеспечивает это.

У меня есть функция, которая в большинстве случаев возвращает один элемент. В частном случае он возвращает вектор. Как эффективно проверить, присутствует ли данное значение в возвращаемом значении / значениях функции.? for i=1:n x=somefunc(data) //now x could be single value or vector //say k.

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

Таким образом, все, что было загружено в этот регистр непосредственно перед возвращением функции, будет возвращаемым значением, даже если вы не собираетесь этого делать.

Вы можете использовать опцию-S для генерации кода assembly и посмотреть, что произошло с EAX непосредственно перед инструкцией «ret».

Когда ваша программа проходит в состоянии if , оператор return не завершает функцию. Число, которое вы получили, является результатом неопределенного поведения.

В вашем коде есть несколько ошибок:

  • у вас есть int , которому присваивается значение 1.0 (которое неявно будет cast/converted), не ошибкой как таковой, а неэлегантным.
  • у вас есть оператор return внутри условности, поэтому вы получите возврат только тогда, когда это if истинно

Если вы исправите проблему с возвратом, удалив остальное, то все будет в порядке:)

Что касается того, почему он работает с 4 в качестве входных данных, то это сводится к случайному chance/ некоторому свойству вашей среды, поскольку код, который вы опубликовали, не должен функционировать, так как всегда будет экземпляр при вычислении факториалов для положительного int, где x = 1 и никакого возврата не будет сгенерировано.

В качестве отступления приведу более краткую/краткую функцию: для такой простой функции вы можете рассмотреть тернарный оператор и использовать такую функцию, как:

это функция, которую я использую для своих факториалов и использовал в библиотеке в течение последних 30 или около того лет (с момента моего C дней) 🙂

Из стандартов C:

Вытекание из конца функции эквивалентно возвращению без значения; это приводит к неопределенному поведению в функции, возвращающей значение.

Ваша ситуация такая же, как и эта:

Он печатает 2 на моей машине. Это вызывает зависимость от соглашения и архитектуры. Возвращаемое значение является результатом последнего вычисления выражения, хранящегося в регистре eax.

Как указано в комментарии , это неопределенное поведение. С g++ я получаю следующее предупреждение.

В Visual C++ предупреждение по умолчанию переводится в ошибку

Когда я отключил предупреждение и запустил полученный исполняемый файл, Fun(4) дал мне 1861810763 .

Так почему же он может работать под g++? Во время компиляции условные операторы превращаются в тесты и переходы (или goto). Функция должна что-то возвращать, и самый простой возможный код для компилятора-это следующие строки.

Это согласуется с вашей разборкой.

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

  • Замените функцию переменной и используйте ее в возвращаемом значении

У меня есть запрос sql, где если разница между 2 раза больше 1440, то он разделится на 7, если нет, то вернет фактическое значение. Проблема в том, что я повторяю код в возвращаемом значении. SELECT ‘IF(TIMESTAMPDIFF(MINUTE, now(), end_at) > 1440, TIMESTAMPDIFF(MINUTE, now(), end_at)/ 7.

Я пытаюсь найти способ избежать потери информации о типе в возвращаемом значении для моего метода. У меня есть следующее: val defs0 = Default.mkDefault[Person, Some[String] :: Some[Int] :: HNil](Some(odd) :: Some(42) :: HNil) Использование IntelliJs Add type annotation дает тип.

Просто удалите else из вашего кода:

Похожие вопросы:

Я работаю над проектом под названием MovieDatabase. Для моих методов searchTitle, searchGenre, searchDirector и searchYear предполагается, что эти методы берут подстроку и проверяют, можно ли их.

Я был смущен концепцией,которая описана в php.net для функции is_dir(), она говорит Указывает, является ли данное имя файла каталогом (1)он проверяет,является ли данный параметр каталогом или.

Я использую простой HTML Dom, пытаясь получить строки с веб-сайта. Когда я распечатываю $title[0] внутри функции, она показывает только одну строку, но когда я сохраняю ее в возвращаемом массиве и.

Я не знаю , есть ли у этого вопроса правильное место в SO , если не сказать m, я его передвину. Я привык к Rails , и меня интересует nodeJS , и я хотел бы понять, что означают non blocking связи.

У меня есть функция, которая в большинстве случаев возвращает один элемент. В частном случае он возвращает вектор. Как эффективно проверить, присутствует ли данное значение в возвращаемом значении /.

У меня есть запрос sql, где если разница между 2 раза больше 1440, то он разделится на 7, если нет, то вернет фактическое значение. Проблема в том, что я повторяю код в возвращаемом значении. SELECT.

Я пытаюсь найти способ избежать потери информации о типе в возвращаемом значении для моего метода. У меня есть следующее: val defs0 = Default.mkDefault[Person, Some[String] :: Some[Int] .

Читайте так же:
В какой программе чертят чертежи

Я только начал изучать Swift и наткнулся на типы функций и на то, как их возвращать. Я просто хочу знать, что означает () в возвращаемом значении функции calcDecrement ? Я знаю, что функция.

В Java, когда я заменяю символы в String экранированными символами, символы появляются в возвращаемом значении, хотя их там не было в соответствии с System.out.println . String[][][].

Я пытаюсь вызвать любую из функций в возвращаемом значении этого закрытия, но не могу этого сделать: function count() < var x = 0; return < increment: function() < ++x; >, decrement: function() <.

Методические указания для студентов всех специальностей дневной формы обучения Новосибирск 1999

В методических указаниях рассмотрены основные конструкции встроенного языка математического пакета Mathcad7 Professional и их применение для программирования основных типов вычислительных алгоритмов ( линейных, разветвляющихся и циклов). Изложение сопровождается рассмотрением большого числа примеров и задач, что способствует лучшему усвоению материала.

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

Л.Г.Гузевский, д.ф.-м.н. профессор, заведующий кафедрой

вычислительной техники НГАВТ;

Н.П.Кисленко, к.т.н. доцент кафедры прикладной

2. Программирование c использованием

программ- ФункциЙ MathCad

2.1. Описание программы — функции и локальной оператор

2.2. Обращение к программе-функции Mathcad

Программирование в программе-функции линейных

Программирование в программе-функции

2.5. Программирование в программе-функции циклических алгоритмов

2.6. Возможные использования условного оператора IF.

2.7. Дополнительные операторы программирования циклов

в пакете Mathcad

3. Модульное программирование в Mathcad

3.1.Модульное программирование в пределах одного

3.2.Модульное программирование в нескольких документах

4. ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ О ПАКЕТЕ

5. РЕКОМЕНДУЕМАЯ ЛИТЕРАТУРА

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

Широкую известность и заслуженную популярность еще в середине 80-х годов приобрели интегрированные системы для автоматизации математических расчетов класса MathCAD, разработанные фирмой MathSoft (США) [1,2]. По сей день они остаются единственными математическими пакетами, в которых описание решения математических задач дается с помощью привычных математических формул и знаков. Такой же вид имеют и результаты вычислений.

В последних версиях MathCAD6Plus и MathCAD7 Professional [1-3] пользователям предоставлена возможность составлять "собственные" программы-функции и использовать принципы модульного программирования для реализации оригинальных вычислительных алгоритмов пользователя. Однако в литературе эти новые возможности освещены весьма слабо. Поэтому в данных указаниях излагаются способы программирования различных алгоритмов с использованием конструкций пакета MathCAD7Professional. За исключением некоторых конструкций, описанных в параграфе 2.7 эти способы реализуются и в пакете MathCAD6Plus.

Программирование c использованием программ-функций MathCad

Напомним, что реализовать тот или иной алгоритм вычисления в пакете Mathcad можно двумя способами:

вставляя соответствующие операторы или функции в текст документа Mathcad. Такой способ называется программированием в тексте документа;

используя так называемые программы-функции, которые содержат конструкции, во многом подобные конструкциям таких языков как Pascal или FORTRAN : операторы присваивания, операторы циклов, условные операторы и т.д. Написание программ — функций в Mathcad позволяет решить задачи, которые невозможно решить используя только операторы и функции Mathcad. Такой способ будем называть программированием в программе-функции . Такое программирование включает два этапа:

Рассмотрим отдельно эти два этапа.

2.1. Описание программы — функции

и локальной оператор присваивания

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

Каждая программа-функция Mathcad имеет оригинальное имя , используя которое осуществляется обращение к этой программе-функции. Через это же имя ( и только через это имя ) “возвращается” в рабочий документ результат выполнения программы-функции.

После имени программы-функции идет список формальных параметров , заключенный в круглые скобки. Через формальные параметры "внутрь" программы-функции “передаются” данные необходимые для выполнения вычислений внутри программы . В качестве формальных параметров могут использоваться имена простых переменных, массивов и функций. Формальные параметры отделяются друг от друга запятой.

Замечание 2.1. Программа-функция может не иметь формальных параметров и тогда данные передаются через имена переменных, определенных выше описания программы-функции. 

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

Порядок описания программы — функции Math cad . Для ввода в рабочий документ описания программы-функции необходимо выполнить следующие действия:

ввести имя программы-функции и список формальных параметров, заключенный в круглые скобки (см. Замечание 6.1 );

ввести символ “:” — на экране отображается как “: =”;

открыть наборную панель Программирования (см. параграф 4.1) и щелкнуть кнопкой “Add line” . На экране появится вертикальная черта и вертикальный столбец с двумя полями ввода для ввода операторов, образующих тело программы-функции ( см. рис. 2.1).

Рис. 2.1. Структура программы-функции

перейти в поле 1 ( щелкнув на нем мышью или нажав клавишу [Tab] ) и ввести первый оператор тела программы-функции. Так как самое нижнее поле всегда предназначено для определения возвращаемого программой значения, то поля ввода для дополнительных операторов открываются с помощью щелчка на кнопке “Add line” панели программирования. При этом поле ввода добавляется внизу выделенного к этому моменту оператора. Для удаления того или иного оператора или поля ввода из тела программы-функции, нужно заключить его в выделяющую рамку и нажать клавишу [Delete] ( см. рис. 2.2) ;

Читайте так же:
Восстановление закладок в яндекс браузере

Рис. 2.2. Добавление операторов в тело программы-функции

заполнить самое нижнее поле ввода ( поле 2 ), введя туда выражение, определяющее возвращаемое через имя программы-функции значение ( см. рис. 2.3 ).

В приведенном примере формальным параметром является простая переменная x , тело программы включает два локальных оператора присваивания ( см. следующий пункт ) и значение переменной z определяет возвращаемый через имя функции результат выполнения программы-функции.

Рис. 2.3. Окончательная структура программы-функции

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

< имя — переменной > < выражение >

Внимание ! Использование "обычного" оператора присваивания ( обозначается : = ) в теле программы-функции приводит к синтаксической ошибке.

2.2. Обращение к программе — функции Math cad

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

< имя — программы > ( список фактических параметров )

Фактические параметры указывают при каких конкретных значениях осуществляются вычисления в теле программы. Фактические параметры отделяются друг от друга запятой.

Очевидно, что между фактическими и формальными параметрами должно быть соответствие по количеству, порядку следования и типу . Последнее соответствие означает:

если формальным параметром является простая переменная, то в качестве фактического может использоваться константа, переменная, арифметическое выражение;

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

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

Замечание 2.2. Обращение к программе-функции должно находиться после описания программы-функции и к моменту обращения фактические параметры должны быть определены. 

Пример 2.1. Обращение к программе f(x), приведенной на рис. 2.3 может иметь следующий вид:

Заметим, что переменная z никак не связана с “локальной” переменной z, используемой внутри тела программы-функции.

Замечание 2.3. Передать данные внутрь программы-функции можно используя внутри программы переменные, определенные до описания программы-функции. Например :

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

Замечание 2.4. Имена фактических параметров при вызове программы-функции могут не совпадать с именами ее формальных параметров. 

2.3. Программирование в программе-функции

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

Пример 2.2 . Оформим в виде программы-функции вычисление корней квадратного уравнения ax 2 + bx +c = 0 по формуле

Для этого введем следующее описание программы-функции

Программа qq1 имеет четыре параметра: смысл первых трех понятен, а четвертый определяет знак перед корнем квадратным — задавая Sig1=1, получаем корень x 1 ; Sig1= — 1, получаем корень x 2 . Программа реализует линейный алгоритм — все операторы выполняются всегда строго последовательно. 

2.4. Программирование в программе-функции

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

Пример 2.3. Переменная y задается следующим выражением

Видно, что алгоритм вычислений содержит две ветви и выбор зависит от значения переменной x. 

Для программирования разветвляющихся алгоритмов в Mathcad имеется условная функция if и условный оператор . Используя эти конструкции можно "изменить" последовательное выполнение операторов. В этих конструкциях могут использоваться следующие новые понятия.

Выражения отношений. Эти выражения используются для сравнения двух арифметических выражений между собой. Выражение отношений записываются в виде :

< выр. А > < знак отношения > < выр. В> ,

где в качестве знака отношения выступают символы, приведенные в таблице 1. Если заданное отношение выполняется, то выражение отношений принимает значение равное 1 ( "истина" ), в противном случае — 0 ( "ложь").

программно нажмите клавишу ввода после запуска файла .exe в Matlab

В Matlab я могу запускать внешние файлы .exe, которые иногда имеют всплывающее окно, требующее нажатия клавиши ввода. Например:

Запустит Winzip, а затем, чтобы использовать его, вам нужно перейти во всплывающее окно «Купить сейчас», нажав Enter. Теперь моя проблема не в winzip, я привел его только в качестве примера (я все равно использую winrar :).

Как я могу программно нажать клавишу ввода в Matlab в таких случаях? (Я использую win 7)

Можно ли использовать прослушиватель событий для решения этой проблемы?

РЕДАКТИРОВАТЬ: класс java.awt.Robot действительно работает в проводнике, но не в любом программном обеспечении, в котором есть всплывающее окно с кнопкой OK, которую необходимо нажать. Я не знаю, почему это не работает. Я привел пример winzip, потому что предполагаю, что у всех на компьютере установлен winzip / winrar. Фактическое программное обеспечение, которое у меня есть, отличается и не имеет отношения к вопросу.

5 ответов

Есть способ использовать Java из Matlab, в частности класс java.awt.Robot . См. здесь.

По-видимому, существует два типа программ относительно того, как они работают при вызове из Matlab с помощью system(‘. ‘) :

Для некоторых программ Matlab ждет завершения программы перед выполнением следующего оператора. Это происходит, например, с WinRAR (по крайней мере, на моем компьютере с Windows 7).

Для других программ этого не происходит, и Matlab переходит к следующему оператору сразу после запуска внешней программы. Примером этого типа является explorer (стандартный файловый менеджер Windows).

Теперь можно немедленно вернуть выполнение в Matlab даже для программ типа 1: просто добавьте & в конец строки, переданной в system . Это стандарт в оболочке Linux Bash, и он также работает в Windows, как обсуждалось здесь.

Читайте так же:
Браузер опера плохо работает

Итак, вы должны поступить следующим образом:

Пакет Python pywinauto может ожидать любое диалоговое окно и автоматически нажимать кнопки. Но он подходит только для собственных и некоторых приложений .NET. У вас могут возникнуть проблемы с нажатием кнопки WPF (возможно, кнопка QT активна — не отмечена), но в этом случае может помочь код вроде app.DialogTitle.wait(‘ready’).set_focus(); app.DialogTitle.type_keys(‘‘) . Ваш случай довольно прост и, вероятно, хватит некоторых хитростей с pywinauto. Ваше «приложение со всплывающим окном» 64-битное или 32-битное?

Функции wait и wait_not имеют параметр тайм-аут . Но если вам нужен именно слушатель с потенциально бесконечным циклом, ожидающим всплывающих окон, хорошее направление — глобальные хуки Windows (pyHook может прослушивать события мыши и keybd, но не может прослушивать открытие диалогового окна). Я постараюсь найти свой прототип, способный обнаруживать новые окна. Он использует обработчики событий API автоматизации пользовательского интерфейса . и . операции . для этого требуется IronPython. Я до сих пор не знаю, как настроить обработчик UI Automation с COM-интерфейсом из стандартного CPython.

РЕДАКТИРОВАТЬ (2019, январь): новый модуль win32hooks был реализован в pywinauto некоторое время назад. Пример использования находится здесь: examples / hook_and_listen.py.

Если вам нужно запустить консольную программу в контексте, который разрешает полное перенаправление DOS, вы можете создать файл с именем, скажем, CR.txt, содержащий возврат каретки, и использовать нотацию « 3

Существует небольшая утилита javascript, которая имитирует подобные нажатия клавиш в интерпретаторе javascript Windows.

Просто создайте файл js со следующим кодом:

Затем вызовите его из Matlab после необходимого тайм-аута следующим образом:

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

Если ваши приложения работают только на платформе Windows, вы можете попробовать использовать объекты .net .

Метод SendWait объекта SendKeys позволяют отправлять практически любую клавишу или комбинацию клавиш в приложение, которое имеет фокус, включая клавиши-модификаторы, такие как Alt , Shift , Ctrl и т. д.

Первое, что нужно сделать, это импортировать библиотеку .net , тогда полный синтаксис для отправки клавиши ENTER будет следующим:

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

Небольшой пример с блокнотом

Как объясняется в документации Microsoft , класс SendKeys может иногда иметь некоторые проблемы с синхронизацией, поэтому, если вы хотите выполнить сложные манипуляции (например, Tab несколько раз, чтобы изменить кнопку вы действительно хотите нажать), возможно, вам придется ввести pause в вызовы Matlab к SendKeys .

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

В моем случае, например, я запускаю все свои данные с внешнего жесткого диска с помощью функции ECO, которая переводит их в режим ожидания, поэтому, когда я вызвал диалоговое окно «Сохранить как . », требуется время, чтобы дисплей, потому что жесткий диск должен проснуться. Если бы я не ввел pause(1) , иногда путь к файлу был бы неполным (первая часть пути была отправлена ​​до того, как диалог получил фокус) .

Также не забывайте символ & при выполнении внешней программы. Вся благодарность Луису Мендо за его выделение. (Я часто забываю, насколько это важно, потому что использую его по умолчанию. Я опускаю его только в том случае, если мне нужно специально дождаться возвращаемого значения из программы, в противном случае я пусть он работает сам по себе)

Почему большинство языков программирования поддерживают возврат только одного значения из функции? [закрыто]

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

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

Есть ли объяснение этому?

Некоторые языки, такие как Python , изначально поддерживают множественные возвращаемые значения, в то время как некоторые языки, такие как C #, поддерживают их через свои базовые библиотеки.

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

    Функции, которые возвращают несколько значений, трудно назвать четко .

Легко ошибиться в порядке возврата значений

(По этой же причине многие люди избегают иметь слишком много параметров для функции; некоторые даже считают, что функция никогда не должна иметь два параметра одного типа!)

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

Потому что функции — это математические конструкции, которые выполняют вычисления и возвращают результат. Действительно, многое из того, что находится «под колпаком» не многих языков программирования, фокусируется исключительно на одном входе и одном выходе, при этом несколько входов являются просто тонкой оболочкой для ввода — и когда вывод одного значения не работает, используя один связная структура (или кортеж, или Maybe ) будет выходом (хотя это «одиночное» возвращаемое значение состоит из множества значений).

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

Читайте так же:
Мсн новости россии и мира актуальные видео

В математике «четко определенная» функция — это функция, в которой для данного входа имеется только 1 выходной сигнал (в качестве примечания вы можете иметь только одну функцию ввода и при этом семантически получать несколько входов, используя каррирование ).

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

Для типов функций, о которых вы говорите (т. Е. Функций, которые возвращают несколько значений разных типов ), я вижу это немного по-другому, чем кажется: я вижу необходимость / использование out-параметров в качестве обходного пути для улучшения дизайна или более полезная структура данных. Например, я бы предпочел, чтобы *.TryParse(. ) методы возвращали Maybe<T> монаду вместо использования параметра out. Подумайте об этом коде в F #:

Поддержка компилятора / IDE / анализа очень хороша для этих конструкций. Это решило бы большую часть «потребности» в наших параметрах. Честно говоря, я не могу думать о каких-либо других методах, где это не было бы решением.

Для других сценариев — тех, которые я не могу вспомнить — достаточно простого кортежа.

В дополнение к тому, что уже было сказано, когда вы смотрите на парадигмы, используемые в сборке, когда функция возвращает функцию, она оставляет указатель на возвращаемый объект в определенном регистре. Если бы они использовали переменные / множественные регистры, вызывающая функция не знала бы, где получить возвращенные значения, если эта функция была в библиотеке. Так что это затруднит соединение с библиотеками, и вместо того, чтобы устанавливать произвольное количество возвращаемых указателей, они идут с одним. Языки более высокого уровня не имеют такого же оправдания.

Во многих случаях использования, где вы бы использовали несколько возвращаемых значений в прошлом, просто больше нет необходимости с современными языковыми функциями. Хотите вернуть код ошибки? Бросить исключение или вернуть Either<T, Throwable> . Хотите вернуть необязательный результат? Вернуть Option<T> . Хотите вернуть один из нескольких типов? Возврат Either<T1, T2> или помеченный союз.

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

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

Рубин

питон

Scala

Haskell

Perl6

Реальная причина того, что одно возвращаемое значение настолько популярно, — это выражения, которые используются во многих языках. На любом языке, где у вас может быть выражение, которое x + 1 вы уже рассматриваете в терминах единичных возвращаемых значений, потому что вы оцениваете выражение в своей голове, разбивая его на части и определяя значение каждого элемента. Вы смотрите x и решаете, что это значение равно 3 (например), и вы смотрите на 1, а затем вы смотрите на x + 1 и сложите все вместе, чтобы решить, что значение целого равно 4. Каждая синтаксическая часть выражения имеет одно значение, а не любое другое число значений; это естественная семантика выражений, которую все ожидают. Даже когда функция возвращает пару значений, она все равно действительно возвращает одно значение, которое выполняет работу с двумя значениями, потому что идея функции, которая возвращает два значения, которые каким-то образом не заключены в одну коллекцию, слишком странная.

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

Perl — это другой язык, который иногда может действовать так, как будто функции возвращают несколько значений, хотя обычно считается, что он возвращает список. Способ, которым списки «интерполируют» в Perl, дает нам списки, подобные (1, foo(), 3) которым могут иметь 3 элемента, как и ожидалось бы большинству людей, которые не знают Perl, но могут с легкостью иметь только 2 элемента, 4 элемента или любое большее количество элементов в зависимости от foo() , Списки в Perl сведены так, что синтаксический список не всегда имеет семантику списка; это может быть просто часть большого списка.

Другим способом заставить функции возвращать несколько значений было бы иметь альтернативную семантику выражения, где любое выражение может иметь несколько значений, и каждое значение представляет возможность. Возьмем еще x + 1 раз, но на этот раз представьте, что у x него есть два значения <3, 4>, тогда значения x + 1 будут <4, 5>, а значения x + x будут <6, 8>или, возможно, <6, 7, 8>в зависимости от того, разрешено ли в одной оценке использовать несколько значений для x . Подобный язык может быть реализован с использованием обратного отслеживания, аналогичного тому, который использует Prolog, чтобы дать несколько ответов на запрос.

Короче говоря, вызов функции — это единственная синтаксическая единица, а единственная синтаксическая единица имеет одно значение в семантике выражения, которую мы все знаем и любим. Любая другая семантика вынудит вас к странным способам действий, таким как Perl, Prolog или Forth.

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

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

Из трех первых языков, Fortran, Lisp и COBOL, первый использовал одно возвращаемое значение, которое было смоделировано по математике. Второе возвращало произвольное количество параметров так же, как оно получило их: в виде списка (можно также утверждать, что он только передал и возвратил единственный параметр: адрес списка). Третье возвращает ноль или одно значение.

Читайте так же:
Бесплатные программы для редактирования аудиофайлов

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

Когда появился C, находясь под влиянием предшествующих языков, он уделял большое внимание эффективному использованию аппаратного ресурса, сохраняя тесную связь между тем, что делал язык C, и машинным кодом, который его реализовывал. Некоторые из его самых старых функций, таких как переменные «auto» и «register», являются результатом этой философии проектирования.

Следует также отметить, что ассемблер был широко популярен до 80-х годов, когда он, наконец, начал постепенно вытесняться из основного развития. Люди, которые писали компиляторы и создавали языки, были знакомы с ассемблером и, по большей части, придерживались того, что там работало лучше всего.

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

Итак, давайте рассмотрим ассемблер. Давайте сначала посмотрим на 6502 , микропроцессор 1975 года, который классно использовался в микрокомпьютерах Apple II и VIC-20. Он был очень слабым по сравнению с тем, что использовалось в мэйнфреймах и миникомпьютерах того времени, хотя и был мощным по сравнению с первыми компьютерами 20, 30 лет назад, на заре языков программирования.

Если вы посмотрите на техническое описание, у него есть 5 регистров плюс несколько однобитовых флагов. Единственным «полным» регистром был счетчик программ (ПК) — этот регистр указывает на следующую команду, которая должна быть выполнена. Другие регистры, где аккумулятор (A), два «индексных» регистра (X и Y) и указатель стека (SP).

Вызов подпрограммы помещает ПК в память, указанную SP, а затем уменьшает SP. Возврат из подпрограммы работает в обратном порядке. Можно помещать и извлекать другие значения из стека, но сложно обратиться к памяти относительно SP, поэтому написание подпрограмм с повторным входом было затруднено. То, что мы считаем само собой разумеющимся, вызывая подпрограмму в любое время, когда мы чувствуем, было не так распространено в этой архитектуре. Часто создается отдельный «стек», чтобы параметры и адрес возврата подпрограммы оставались раздельными.

Если вы посмотрите на процессор, который вдохновил 6502, 6800 , у него был дополнительный регистр, регистр индекса (IX), такой же широкий, как SP, который мог принимать значение от SP.

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

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

8080 , используемый на ТРС-80 и множество CP / M микрокомпьютеров на основе могли бы сделать что — то похожее на 6800, нажав SP на стек , а затем выскакивают его на косвенном регистре, HL.

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

Проблема в том, как вы что-то возвращаете ? Регистры процессора были не очень многочисленными на раннем этапе, и часто приходилось использовать некоторые из них, даже чтобы выяснить, к какой части памяти обращаться. Возврат вещей в стеке будет сложным: вам нужно будет выгрузить все, сохранить ПК, передать возвращаемые параметры (которые будут храниться где-то еще?), Затем снова нажать ПК и вернуться.

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

Давайте посмотрим на язык, который допускает множественные возвращаемые значения: Forth. То, что делает Форт, — это хранение отдельного стека возврата (RP) и стека данных (SP), так что все, что нужно было сделать функции, — это вытолкнуть все ее параметры и оставить возвращаемые значения в стеке. Поскольку стек возвратов был отдельным, он не мешал.

Как человек, который выучил ассемблер и Форт за первые шесть месяцев работы с компьютерами, множественные возвращаемые значения выглядят для меня совершенно нормально. Такие операторы, как операторы Форта /mod , которые возвращают целочисленное деление, а остальные — кажутся очевидными. С другой стороны, я легко вижу, как кто-то, чей ранний опыт был С-умом, находит эту концепцию странной: она идет вразрез с их укоренившимися ожиданиями о том, что такое «функция».

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

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

голоса
Рейтинг статьи
Ссылка на основную публикацию
Adblock
detector