Диспетчерские функции в Джулия версии v0.5+


Согласно списку изменений для Джулии 0.5,

Каждая функция и замыкание теперь имеют свой собственный тип.
Означает ли это, что теперь можно предоставить более подробную информацию функции более высокого порядка, например foo(bar :: Function{Float64}) = ..., в отличие от pre-0.5, где Тип bar не может быть более конкретным, чем Function?

Если да, то как это правильно сделать? Если нет, то каков фактический импорт этого изменения, помимо того, что компилятор может лучше оптимизировать сгенерированный код? ТИА.

1 4

1 ответ:

На самом деле нет. Я понимаю, к чему вы клоните, и мне это нравится, но это невозможно. (Конечно, не сейчас, а возможно, и никогда. Может, однажды, используя черты характера.)

Давайте рассмотрим пример: foo и bar

julia> foo(x::String) = println(x)
foo (generic function with 1 method)

julia> foo(x::Int64) = println(x+1)
foo (generic function with 2 methods)

julia> bar(x...) = println(x)
bar (generic function with 1 method)

Какова иерархия типов для foo?

julia> typeof(foo)
#foo

julia> supertype(typeof(foo))
Function

julia> supertype(supertype(typeof(foo)))
Any
Таким образом, мы видим, что тип функции foo является #foo, который является подтипом Function. Обратите внимание, что # означает, что это сгенерированное имя, вы не можете поместить хэш в имена, когда просто пишете код, но Джулия компилятор (используя термин свободно) может.

Почему его супер-супертип не является более конкретным, чем просто функция? Что бы это могло быть? Function{Int64} или Function{String}? функции в julia, не имеют сигнатур типа, методы делают. Функция-это просто имя для множественной отправки, метод-это то, что на самом деле отправляется. Грубо говоря, имя функции говорит, в какой таблице я должен искать, а типы аргументов (т. е. это сигнатура типа) являются ключом для поиска, в эта таблица. Метод сам по себе является тем, что возвращается, используя этот ключ.

Итак, давайте продолжим наш пример и посмотрим, что мы можем сделать:
julia> dothing(f::typeof(foo)) = f(rand([randstring(), rand(Int64)]))
dothing (generic function with 1 method)

julia> dothing(foo)
3139374763834167054

julia> dothing(foo)
Ed2kNGrd


julia> dothing(bar)
ERROR: MethodError: no method matching dothing(::#bar)
Closest candidates are:
  dothing(::#foo) at REPL[11]:1
Таким образом, мы успешно ограничили dothing, чтобы только принять #foo в качестве аргумента. Смотрите, он выдает ошибку, когда вы даете ему #bar. Это не очень полезно, Так как функция foo является единственной вещью типа #foo.

Мы могли бы использовать Union хотя:

julia> dootherthing(f::Union{typeof(foo),typeof(bar)}) = f(rand([randstring(), rand(Int64)]))
dootherthing (generic function with 1 method)

julia> dootherthing(foo)
9107791406050657562

julia> dootherthing(foo)
SmB2Xmw8

julia> dootherthing(bar)
("1IpZIMnx",)

julia> dootherthing(bar)
(-6356894350805213697,)


julia> dootherthing(str)
ERROR: UndefVarError: str not defined

julia> dootherthing(string)
ERROR: MethodError: no method matching dootherthing(::Base.#string)
Closest candidates are:
  dootherthing(::Union{#bar,#foo}) at REPL[19]:1

dootherthing принимает a #foo или a #bar. Либо функция завод.

Это имеет ограниченное применение, как белый список.