2016-10-04 51 views
4

朱莉婭郎文檔解釋瞭如何內部構造和新的()函數可用於構建自我指涉的對象:一代自我指涉不變類型在朱莉婭的

type SelfReferential 
     obj::SelfReferential 
     SelfReferential() = (x = new(); x.obj = x) 
    end 

但是這種方法不適合一成不變工作類型,因爲它基本上使用未完成初始化的實例x的變種。

如何在Julia中生成一個自引用的不可變對象?

+4

我想你已經回答了你自己的問題 - 你不能。 –

+1

此外,你爲什麼要? –

+0

@David,創建高性能,不可變的遞歸數據結構。我知道要做到這一點的唯一方法是通過抽象類型來實現,而這種抽象類型應該會影響性能。我不明白什麼是一個類型的不變性概念應該禁止一個自我指涉的不可變的? – Bernd

回答

3

既然您之前似乎已經使用了Haskell,我將從函數式編程的角度定製這個答案。自引用不可變類型的常見用例是創建一個懶列表。

作爲一種嚴格的(即不是懶惰的)語言,不可變的對象不可能直接引用它自己。

但是,這並不排除間接引用其自身,使用可變對象,如RefVector

對於懶結構的特殊情況,我可能會建議將可變性限制在一個特殊的對象上,比如Lazy{T}。例如,

import Base: getindex 
type Lazy 
    thunk 
    value 
    Lazy(thunk) = new(thunk) 
end 

evaluate!(lazy::Lazy) = (lazy.value = lazy.thunk(); lazy.value) 
getindex(lazy::Lazy) = isdefined(lazy, :value) ? lazy.value : evaluate!(lazy) 

然後,例如,它可以做一個簡單的懶惰名單如下:

import Base: first, tail, start, next, done, iteratorsize, HasLength, SizeUnknown 
abstract List 
immutable Cons <: List 
    head 
    tail::Lazy 
end 
immutable Nil <: List end 

macro cons(x, y) 
    quote 
     Cons($(esc(x)), Lazy(() -> $(esc(y)))) 
    end 
end 

first(xs::Cons) = xs.head 
tail(xs::Cons) = xs.tail[] 
start(xs::Cons) = xs 
next(::Cons, xs) = first(xs), tail(xs) 
done(::List, ::Cons) = false 
done(::List, ::Nil) = true 
iteratorsize(::Nil) = HasLength() 
iteratorsize(::Cons) = SizeUnknown() 

這的確作品,因爲它會像Haskell這樣的語言:

julia> xs = @cons(1, ys) 
Cons(1,Lazy(false,#3,#undef)) 

julia> ys = @cons(2, xs) 
Cons(2,Lazy(false,#5,#undef)) 

julia> [take(xs, 5)...] 
5-element Array{Int64,1}: 
1 
2 
1 
2 
1 

此功能可能看起來很複雜,但幸運的是已經在Lazy.jl中實施。


重要的是要指出,由於類型不穩定和可變類型,上面的代碼會產生很多開銷。如果您使用immutable的目標不是表現力,而是表現力,那麼顯然這樣的做法是不恰當的。但是一般情況下不可能有一個引用自身的堆棧分配結構,所以在需要最大性能的情況下,最好避免完全自行引用。

+0

感謝您的詳細解答。我完全擔心表演。您建議的方法與FunctionalCollections.jl中的PersistentList非常相似。然而它意味着使用抽象類型,並且使用這樣的代碼運行@code_warntype,顯示了很多紅色警告,又名Union {Cons,Nil},所以我擔心性能。但是,在堆棧分配的結構中,最後一句自引用不可能解釋給我。 – Bernd

+2

@Bernd列表實際上可以非常高效(儘管懶惰列表不那麼如此)。定義一個性能列表的方法是使用'typealias List {T} Nullable {Cons {T}}',這樣可以避免類型不穩定。 –

+1

如果你想讓列表既是高性能又是自引用的,那麼只需使用'type'而不是'immutable'。 –