2015-10-04 2 views
2

(с использованием Julia 0.3.11) У меня возникли проблемы со шрифтом - аннотирование корректно некоторых из моего кода в исходной версии, которую мы использовали ASCIIString - для аннотации любая строка, «избегать» абстрактных типов, но давайте начнем с примера, это может быть связано с тем, что я видел реферируемых как «треугольной отправки» в некоторых дискуссиях здесь:Функциональные подписи и подтипы Julia, в частности String, ByteString

# How to type annotate this (sortof "Dictionary with default) 
function pushval!(dict, key, val) 
    key in keys(dict) ? push!(dict[key], val) : dict[key] = [val] 
    return dict 
end 

d1 = Dict{ASCIIString, Vector{Int}}() 
d2 = Dict{String, Vector{Int}}() 

pushval!(d1, "a", 1) 
pushval!(d2, "a", 1) 

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

Итак, теперь я попытался набрать аннотированный текст:

function pushval!{K, V} (dict::Dict{K, Vector{V}} , key, val) 

Многое больше документирует и работает. Но теперь наступает более сложная часть - я хочу, чтобы «ключ» был любым подтипом K, а val - любые подтипы V (справа?), Например - я хотел бы сделать словарь String - который является абстрактным типом, но использовать конкретные ключи - которые AsciiString/байтовой строки/UTF8String,

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

function pushval!{K, V} (dict::Dict{K, Vector{V}} , key::KK <: K, val:: VV <: V) 
function pushval!{K, V, KK <: K, VV <: V} (dict::Dict{K, Vector{V}} , key::KK, val::VV) 

одно из решений, как предполагают, в (Can I use a subtype of a function parameter in the function definition?) что-то с «новообращенного».

Но все это заставило меня задуматься о коде Юлии, который я пишу, я начал писать систему - используя String, FloatingPoint, Number и такие абстрактные типы, когда я действительно пытался запустить его, я вернули, чтобы преобразовать все в конкретные типы только для того, чтобы получить работу на данный момент ...

Есть ли рекомендуемая кодовая база для чтения в качестве ссылки на идиоматический код Юлии? Как и сама реализация словаря Julia, присваиваем оператор даже. Есть ли часть стандартной библиотеки, которую можно считать полезной для начала? благодаря

ответ

1

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

То, что вы называете pushval!, может быть достигнуто с помощью push!(get!(d1, "a", []), 1) (хотя оно вернет значение словаря, которое было добавлено вместо самого словаря). Если необходимо ограничить тип значений внутренней коллекции, вы можете, например, использовать:

push!(get!(d1, "a", Number[]), 1) 

Если вам действительно нужно определить это как функция, я боюсь, что, на данный момент, вы не можете определите типы в том, как вы описываете. Как accepted answer на вопрос, на который вы ссылаетесь, Julia еще не реализует треугольную отправку, хотя it is targeted for 0.5.

+0

Это здорово знать, так что это случай «треугольной отправки» в конце концов. и я не знал о получении!(), которая является идиомой, в которой я нуждаюсь здесь! благодаря! – oyd11

+0

В: Я попытался добавить 'key :: K; val :: V; '- как утверждения типа при входе функции. Хотя на REPL - они, кажется, дают утверждения, которые я ожидаю - внутри функции - они, кажется, игнорируются, я должен был написать их как «@assert (typeof (key) <: K) и т. Д., Что я и думал «key :: K» сделал бы, какой-нибудь ввод? – oyd11

+1

У меня есть подозрение, но я не уверен, что я имею в виду то же самое. Не могли бы вы разместить еще какой-нибудь код? (Может быть, вы должны задать это как еще один вопрос?) – user4235730

1

Хотя мне не нравится это это решение очень (низкая производительность), это может быть полезно:

function pushval!{K, V} (dict::Dict{K, Vector{V}} , key , val) 
    fun = function inner{tt1<:K,tt2<:V}(key::tt1,val::tt2) 
    key in keys(dict) ? push!(dict[key], val) : dict[key] = [val] 
    return dict 
    end 
    return fun(key,val) 
end 
# => pushval! (generic function with 1 method) 
d1 = Dict{ASCIIString, Vector{Int}}() 
# => Dict{ASCIIString,Array{Int32,1}} with 0 entries 
d2 = Dict{String, Vector{Int}}() 
# => Dict{String,Array{Int32,1}} with 0 entries 

pushval!(d1, "a", 1) 
# => Dict{ASCIIString,Array{Int32,1}} with 1 entry: 
# "a" => [1] 

pushval!(d2, "a", 1) 
# => Dict{String,Array{Int32,1}} with 1 entry: 
# "a" => [1] 
0

Я мог рекомендую смотреть на Julia Style Guide. Есть несколько советов по использованию аннотаций типа.

Для вашего случая вам не нужны аннотации типов для функции pushval!. Julia получит достаточно информации от Dict создания и вывода соответствующих типов для аргументов pushval!.

function pushval!(dict, key, val) 
    key in keys(dict) ? push!(dict[key], val) : dict[key] = [val] 
    return dict 
end 

d = Dict{String, Vector{Int} # Here is all annotations you need. 

pushval!(d, "a", 1) # OK, "a" is ASCIIString which is subtype of AbstractString 
pushval!(d, 1, 1) # ERROR, 1 is Int64 which is not subtype of AbstractString 
+0

Я знаю, что это работает, вот как это работает в моем производственном коде в течение нескольких месяцев. Руководство по стилю - хорошая рекомендация, хотя руководство по «другому» стилю больше подходит к тому, что я думаю [https://github.com/johnmyleswhite/Style.jl]. директива «Не вводить явно правило параметрического типа для функции, если это не требуется для обеспечения правильности». Для правильности важно, чтобы «dict» был массивом dict-> (что-то), и этот «ключ» является подтипом ключа и т. Д. Выполнение меньше - недостаточно документировано и дает несколько загадочных сообщений об ошибках, если вызывается с неправильными аргументами. – oyd11

Смежные вопросы