Диспетчерские функции в Джулия версии v0.5+
Согласно списку изменений для Джулии 0.5,
Каждая функция и замыкание теперь имеют свой собственный тип.Означает ли это, что теперь можно предоставить более подробную информацию функции более высокого порядка, например
foo(bar :: Function{Float64}) = ...
, в отличие от pre-0.5, где Тип bar
не может быть более конкретным, чем Function
?
Если да, то как это правильно сделать? Если нет, то каков фактический импорт этого изменения, помимо того, что компилятор может лучше оптимизировать сгенерированный код? ТИА.
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
. Либо функция завод.