5 ms·
When I looked at Julia last time I do not think it had the capability to partially apply tensors. In Spiral indexing into a 3d tensor would give you back a 2d t
by abstractcontrol 8y ago
When I looked at Julia last time I do not think it had the capability to partially apply tensors. In Spiral indexing into a 3d tensor would give you back a 2d tensor. It might be possible to do this with function in Julia, but that would depend on its inlining capabilities and unlike Spiral it does not provide guarantees with regards to that.
Its type system is definitely less powerful than Spiral's - some of the things you could express naturally in Spiral would require macros in Julia.
All in all, the language strikes me as a better Matlab which I think it succeeds at, but Spiral is made to be a better F#. Some of the tradeoffs I had to make in language design means that I could not succeed at this across the board.
The fact that it has a more powerful type system makes it take an immediate hit in terms of ergonomics, and the language is less pleasant to code in than F# because the IDE is not providing immediate and constant feedback.
On the other hand for systems programming, I can't imagine what C (and even C++) could possibly do better than it except maybe compile times. Despite that, Spiral is also nothing ilke Rust - it does not try to check that pointers are safe. It is rather a extremely expressive static language that has no type annotations anywhere and looks like a dynamically typed functional language.
- StefanKarpinski 8y ago> When I looked at Julia last time I do not think it had the capability to partially apply tensors. In Spiral indexing into a 3d tensor would give you back a 2d tensor. It might be possible to do this with function in Julia, but that would depend on its inlining capabilities and unlike Spiral it does not provide guarantees with regards to that. That's exactly how slicing a tensor works in Julia: julia> T = copy(reshape(1:2*3*4, 2, 3, 4)); julia> summary(T) "2×3×4 Array{Int64,3}" julia> T[:,2,:] 2×4 Array{Int64,2}: 3 9 15 21 4 10 16 22 Inlining seems irrelevant since the slicing is done eagerly. Unless you're talking about lazy slicing, in which case you could do `f(T) = T[:,2,:]` and your inlining/function comment makes more sense. If you use StaticArrays.jl (the closest thing in Julia to Spiral's tensors) then the machine code for this operation on a 2×3×4 Float64 tensor is just: vmovups 16(%rsi), %xmm0 vmovups 64(%rsi), %xmm1 vmovups 112(%rsi), %xmm2 vmovups 160(%rsi), %xmm3 vmovups %xmm0, (%rdi) vmovups %xmm1, 16(%rdi) vmovups %xmm2, 32(%rdi) vmovups %xmm3, 48(%rdi) movq %rdi, %rax retq > Its type system is definitely less powerful than Spiral's - some of the things you could express naturally in Spiral would require macros in Julia. The macro comment bit is a bit perplexing since macros are about syntax and are about as unrelated to the type system as it's possible to get. I'm unaware of any way that the presence of absence of macros in a language can affect the expressiveness of its type system. I'd be very curious to hear what can be expressed in Sprial's type system that cannot be in Julia's. Julia's type system is generally more expressive than state-of-the-art dependent static type systems since it punts on type checking entirely. This allows it to have, among other things, parametric types where the parameters can be other types, integers, floats, symbols and tuples of same (recursively).Parametric types even support fancy features like using an earlier type parameters to constrain later type parameters, e.g. `X{T<:Number, S<:Vector{<:T}}` — i.e. `T` is a possibly abstract number type and `S` is a vector whose element type is a subtype of `T`. The only major type system feature I'm aware of Julia lacking (aside from the obvious omission of static type checking) is intersection types. There's been some thought of adding those in order to support multiple inheritance among other things, but it hasn't proven necessary yet.
- abstractcontrol 8y agoI recall an example where Julia had to use macros in order to achieve loop unrolling. I'll dig it up if you want. This is something can be done quite naturally in Spiral due to its type system. I find that people often say macros are about syntax, but what they really are is some combination of a parser and a partial evaluator - in other words, their main use seems to doing compile-time function evaluation. Spiral does not have arbitrary CTFE, but can perform any functionally-pure, non side-effecting computation in its type system plus memoization of function calls. One thing of practical interest that makes me doubt Julia's inlining capabilities would be monads. https://github.com/pao/Monads.jl/blob/master/doc/index.rst https://github.com/pao/Monads.jl/blob/master/doc/index.rst "Monads.jl provides a powerful, if relatively slow" The key word here is slow. I haven't seen a single language as of yet apart from Spiral that can inline all their overheads away. They are pervasive in Haskell, and Haskell cannot do it. Scala wants to do it, but it can't. F# and Ocaml cannot optimize their overheads away. If Julia could then it would advertise it. This is something that is subject of academic research in the field of partial evaluation. Speaking as a functional programmer, as a language Julia feels barely functional to me. It has first class functions, but it does not have pervasive partial application and syntax that makes such a style comfortable like functional languages tend to have. It feels more like an imperative language. And speaking as a systems programmer, I know that without inlining guarantees you cannot have optimized functional constructs. It is not just monads. By tracking all the factions and their bodies to exactness and forgoing all heap allocation unless explicitly stated, it becomes much easier to do language interop. It is possible to make functions that capture variables from lexical scope and then pass as arguments to a function that passes them through to the GPU. Julia talks about speed, but barely talks about inlining so I am dubious about its claims. I could go on, but I think this is a large enough sample of my views on Julia. If Julia wants me to use it, then it needs to speak more to my values as a programmer.
- ChrisRackauckas 8y agoI agree that while Julia has a lot of functional programming elements, it's not strictly a functional programming language. It also is built for things where heap-allocated arrays are necessary: you're not going to be scientific computing with 100GB stack-allocated arrays. Having the base arrays be stack-allocated and then having StaticArrays for stack-allocated arrays works well, though that means you do want to use imperative styles a lot when managing the large array operations to cut down on allocations. Spiral and Julia are just very different and cater to different paradigms and applications.