Различия между 5 типами функций Red и почему они их различают? - PullRequest
4 голосов
/ 24 апреля 2019

В красном есть функции типов данных function!, op!, native!, routine! и action!.Каковы различия между ними?Насколько я знаю, function! используется для пользовательских функций, op! - для инфиксных операторов, routine! - для функций, определенных в Red/System, но зачем нужны две другие?

Ответы [ 3 ]

5 голосов
/ 24 апреля 2019

function!

Как вы уже догадались, function! s являются пользовательскими функциями, которые поддерживают уточнения и проверку типов, а также могут содержать встроенные строки документов.

Как правило, function! значения создаются с помощью конструкторов func, function, does и has и используют так называемый диалект spec ;но, теоретически, ничто не мешает вам создавать свои собственные конструкторы или разрабатывать собственные форматы спецификаций.

Стоит также отметить, что function! s полностью поддерживает отражение.

op!

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

*Значения 1024 *op! ограничены двумя аргументами, не поддерживают уточнения и имеют ограниченную поддержку отражения (например, вы не можете проверять их тела с помощью body-of).

routine!

routines! существуют в обеих сферах Красного и Красного / Системного (низкоуровневый диалект, поверх которого строится среда выполнения Красного).Их спецификации написаны на диалекте spec , но их тела содержат красный / системный код.Да, и они поддерживают рефлексию.

Обычно они используются для привязки библиотек (например, упомянутой вами библиотеки SQL), взаимодействия со средой выполнения или для устранения узких мест в производительности (Red / System - скомпилированный язык, поэтому переписываемкритичные к производительности части вашего приложения в виде набора routine! s дадут вам значительный прирост за счет обязательной компиляции.

native!

native! sфункции, написанные на Red / System (по причинам производительности, простоты или осуществимости) и скомпилированные в собственный код (отсюда и название).Не уверен, что еще можно сказать о них, кроме деталей реализации.native! не очень удобны для пользователя, поэтому вы можете изучить исходный код Red на случай, если у вас остались какие-либо вопросы.

action!

action! s являются стандартизированныминабор функций, написанных на Red / System (точно так же как native! s), которые каждый тип данных реализует (или наследует) как свой «метод».action! полиморфны в том смысле, что они отправляют свой первый аргумент:

>> add 1 2%
== 1.02
>> add 2% 1
== 102%
>> append [1] "2"
== [1 "2"]
>> append "1" [2]
== "12"

В основных языках это обычно выглядит как "1".append([2]) или что-то в этом роде.

Различие между action! s и native! s сводятся к выбору дизайна:

  • вы можете иметь столько native!, сколько хотите, но action! s, для эффективности, имеют фиксированныйТаблица отправки размера (это означает, что максимальное число action! с на тип данных ограничено; минимальное число равно двум: make [для создания значения] и mold [для сериализации значения в string!]).

  • логически, action! s организованы вокруг типа данных, к которому они принадлежат, в одном файле, тогда как native! s на самом деле не имеют отношения к типам данных и реализуют поток управления, тригонометрические функции,операции над сетами и т. д.


Совсем недавно, совсем недавно, у нас подобное обсуждение о action! с и native! с в чате нашего сообщества, который вы можете прочитать.Я также могу порекомендовать просмотреть черновик спецификации Рудольфа Мейера Red и, конечно, официальную справочную документацию .

Что касается "почему" в вашем вопросе - различиемежду 5 типами - это просто деталь реализации, унаследованная от Rebol.Логически все они реализуют то, что вы могли бы назвать «функцией» с концептуальной точки зрения, и попадают в any-function! camp.

3 голосов
/ 24 апреля 2019

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

Я не знаю точно, что делает Red в случае компиляции, случае интерпретатора для Rebol2 и Redпохожи.Эти различные типы фактически являются частью большого оператора switch ().Если он смотрит в ячейку, описывающую «функцию», и находит TYPE_NATIVE, он знает, что должен интерпретировать содержимое ячейки как содержащее указатель на собственную функцию.Если он находит TYPE_FUNCTION, он знает, как выделить ячейку, содержащую указатель на блок кода для выполнения:

https://github.com/red/red/blob/cb39b45f90585c8f6392dc4ccfc82ebaa2e312f7/runtime/interpreter.reds#L752

Теперь я сам согласен с вашей строкой вопросов.например, это утечка деталей реализации пользователю - кого не должен интересовать этот аспект в системе типов?

Но для чего это стоит, существует универсальный набор типов, называемый ANY-FUNCTION!:

>> any-function!
== make typeset! [native! action! op! function! routine!]

И вы могли бы думать об этом как о «всем, что подчиняется функциональному интерфейсу для вызова».Однако есть некоторые сложности, как OP!получает свой первый аргумент слева ... так что это действительно вызывает беспокойство с точки зрения интерфейса.

В любом случае ... НАТИВНО!(тело встроено как исполняемый код в исполняемый файл) против FUNCTION!(тело - это блок кода Red, выполняемый путем интерпретации или компиляции) - это только одно из отличий.Рутина!это фасад, созданный для взаимодействия с DLL / библиотекой а-ля FFI , которая не имела априорных знаний о Red.Действие!это очень упрощенная попытка того, что называется на других языках Generics .ОП!просто получает свой первый аргумент слева.

Дело в том, что каждый из них может ощущаться вызывающим абонентом одинаково (кроме OP!), но реализация должна делать что-то другое.Он знает, как сделать что-то другое, через байт типа в ячейке значения.Вот как это сделал Rebol2 - и Red довольно внимательно следил за Rebol2 - так он это и делает.Это означает, что любая новая концепция того, что обеспечивает реализацию функции, требует нового типа данных, и это, вероятно, не самая лучшая идея.

0 голосов
/ 24 апреля 2019

Красный основан на Реболе и имеет те же типы.

  • функция! - это пользовательская функция, определенная красным
  • native! - это функция в машинном коде
  • op! - это инфиксный оператор, написанный в машинном коде
  • action! - это полиморфная функция в машинном коде
  • рутина! - это функция, импортированная из динамической библиотеки
...