In a similar vein, see this list of complaints against Scala by Edward
Kmett, possibly the most brilliant and prolific Haskell programmer on Earth:

http://www.reddit.com/r/haskell/comments/1pjjy5/odersky_the_trouble_with_types_strange_loop_2013/cd3bgcu

I'll try to comment with my understanding of where Rust stands on each
point:


>    -
>
>    If you take any two of the random extensions that have been thrown
>    into scala and try to use them together, they typically don't play nice.
>    e.g. Implicits and subtyping don't play nice together.
>
>
We have to stay careful, but I think the various parts of Rust's type
system fit together amazingly well right now.



>    -
>
>    Type inference works right up until you write anything that needs it.
>    If you go to write any sort of tricky recursive function, you know, where
>    inference would be useful, then it stops working.
>
> Not completely sure about this, but hopeful. Can anyone else make a
better-informed comment?



>
>    -
>
>    Due to type erasure, its easy to refine a type in a case expression /
>    pattern match to get something that is a lie.
>
>
I don't think Rust has this problem.



>
>    -
>
>    Free theorems aren't.
>
>
This is referring to the idea that if type variables are completely opaque
to a generic function parameterized over them, then you can formulate some
equational theorems for the function "for free", which you know will always
be true, because they can't not be. For example, for the Haskell function
fmap :: forall a b. (a -> b) -> (f a -> fb):

    fmap f . fmap g = fmap (f . g)
    fmap id = id

Due to unrestricted (non-mutation) side effects Rust flunks this, but it
would be nice if, for functions which can be assumed to be pure, it didn't.
For that we have to be vigilant about never allowing things like
dynamic_cast or various built-in intrinsics on completely generic types, at
least outside of unsafe code. This seems more hopeful, but Rust still
flunks it right now: because of, for one instance, size_of::<T>(). I'm not
sure whether there are other instances. It would be nice if this could be
addressed.



>    -
>
>    Since you can pass any dictionary anywhere to any implicit you can't
>    rely on the canonicity of anything. If you make a Map or Set using an
>    ordering, you can't be sure you'll get the same ordering back when you come
>    to do a lookup later. This means you can't safely do hedge unions/merges in
>    their containers. It also means that much of scalaz is lying to itself and
>    hoping you'll pass back the same dictionary every time.
>
> Rust smartly avoids this problem.



>
>    -
>
>    The container types they do have have weird ad hoc overloadings. e.g.
>    Map is treated as an iterable container of pairs, but this means you can't
>    write code that is parametric in the Traversable container type that can do
>    anything sensible. It is one of those solutions that seems like it might be
>    a nice idea unless you've had experience programming with more principled
>    classes like Foldable/Traversable.
>
> Not quite sure what sort of overloadings this is referring to, but if/when
we add an Iterable trait, this means that perhaps the impl for maps should
iterate only over values, rather than key-value pairs, so that it makes
more sense to use the same generic code for both e.g. maps and arrays. (Of
course a (key, value) iterator should still be provided separately.)

When we gain higher-kinded types, we should also be able to add the actual
Foldable and Traversable traits themselves.



>
>    -
>
>    You wind up with code that looks like myMap.map(...).toMap all over
>    the place due to CanBuildFrom inference woes.
>
> No idea what this is about.



>
>    -
>
>    Monads have to pay for an extra map at the end of any comprehension,
>    because of the way the for { } sugar works.
>
> We have neither monads nor sugar at the moment, but if we ever do (not
quite as crazy as it sounds, given that C# also has a version of it in
LINQ), we should presumably try to remember this problem and avoid it.



>
>    -
>
>    You have type lambdas. Yay, right? But now you can't just talk about 
> Functor
>    (StateT s IO). Its Functor[({type F[X] = StateT[S,IO,X]})#F], and you
>    have to hand plumb it to something like return, because it basically
>    can't infer any of that, once you start dealing with transformers ever. The
>    instance isn't directly in scope. 12.pure[({type F[X] =
>    StateT[S,IO,X]})#F] isn't terribly concise. It can't figure out it
>    should use the inference rule to define the implicit for StateT[S,M,_]from 
> the one for
>    M[_] because of the increased flexibility that nobody uses.
>
>
Rust doesn't have type lambdas and almost certainly never will.



>
>    -
>
>    In this mindset and in the same vein as the CanBuildFrom issue, things
>    like Either don't have the biased flatMap you'd expect, somehow
>    encouraging you to use other tools, just in case you wanted to bind on the
>    Left. So you don't write generic monadic code over the Either monad,
>    but rather are constantly chaining foo.right.flatMap(...
>    .right.flatMap(....)) ensuring you can't use the sugar without turning
>    to something like scalaz to fill it in. Basically almost the entire
>    original motivation for all the type lambda craziness came down to being
>    able to write classes like Functor have have several instances for
>    different arguments, but because they are so hard to use nobody does it,
>    making the feature hardly pay its way, as it makes things like unification,
>    and path dependent type checking harder and sometimes impossible, but the
>    language specification requires them to do it!
>
> See above.


>    -
>
>    You don't have any notion of a kind system and can only talk about
>    fully saturated types, monad transformers are hell to write. It is easier
>    for me to use the fact that every Comonad gives rise to a monad
>    transformer to intuitively describe how to manually plumb a semimonoidal
>    Comonad through my parser to carry extra state than to work with a
>    monad transformer!
>
> Rust doesn't have a kind system either, but hopefully it will!


>
>    -
>
>    I've been able to get the compiler to build classes that it thinks are
>    fully instantiated, but which still have abstract methods in them.
>
> I don't believe Rust has this problem.



>
>    -
>
>    Tail-call optimization is only performed for self-tail calls, where
>    you do not do polymorphic recursion.
>
> Rust is a little bit better here (LLVM does "sibling call" optimization,
which is somewhat more general than just self calls), but not by much.



>    -
>
>    Monads are toys due to the aforementioned restriction. (>>=) is called
>    flatMap. Any chain of monadic binds is going to be a series of
>    non-self tailcalls. A function calls flatMap which calls a function, which
>    calls flatMap... This means that non-trivial operations in even the
>    identity monad, like using a Haskell style traverse for a monad over
>    an arbitrary container blows the stack after a few thousand entries.
>
>
Rust is not any better on this front. While we still had segmented stacks
we could've handled this, if not in constant space but at least on the
stack, but we no longer do.

I'm wondering whether the fact that we're going to have moves and drops
statically tracked by the compiler might make it more realistic to think
about TCE again. I think the biggest remaining obstacle would be the
calling convention.



>
>    -
>
>    We can fix this, and have in scalaz by adapting apfelmus' operational
>    monad to get a trampoline that moves us off the stack to the heap, hiding
>    the problem, but at a 50x slowdown, as the JIT no longer knows how to help.
>    -
>
>    We can also fix it by passing imperative state around, and maybe
>    getting scala to pass the state for me using implicits and hoping I don't
>    accidentally use a lazy val. Guess which one is the only viable
>    solution I know at scale? The code winds up less than 1/2 the size and 3x
>    faster than the identity monad version. If scala was the only language I
>    had to think in, I'd think functional programming was a bad idea that
>    didn't scale, too.
>    -
>
>    for yield sugar is a very simple expansion, but that means it has all
>    sorts of rules about what you can't define locally inside of it, e.g. you
>    can't stop and def a function, lazy val, etc. without nesting another
>    for yield block.
>
> Not sure what this is about, but if we ever add a `yield` construct we
should presumably try to take this into consideration.



>    -
>
>    You wind up with issues like 
> SI-3295<https://issues.scala-lang.org/browse/SI-3295>where out of a desire to 
> not "confuse the computation model", it was
>    decided that it was better to you know, just crash when someone folded a
>    reasonably large list than fix the issue.. until it finally affected
>    scalac itself. I've been told this has been relatively recently fixed.
>    -
>
>    No first-class universal quantification means that quantifier tricks
>    like ST s, or automatic differentiation without infinitesimal
>    confusion are basically impossible.
>
>    def test = diff(new FF[Id,Id,Double] {
>       def apply[S[_]](x: AD[S, Double])(implicit mode: Mode[S, Double]): 
> AD[S, Double]
>          = cos(x)
>    })
>
>    is a poor substitute for
>
>    test = diff cos
>
>
> Rust doesn't have this right now either, but in part of my earlier "Type
system thoughts" e-mail I was thinking about how it could potentially be
added.



> ... but it runs on the JVM.
>

Rust doesn't have this excuse. :-)



On Thu, Dec 5, 2013 at 2:07 AM, Ziad Hatahet <[email protected]> wrote:

> To be taken with a grain of salt, naturally:
> https://www.youtube.com/watch?v=TS1lpKBMkgg
>
>
> --
> Ziad
>
> _______________________________________________
> Rust-dev mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/rust-dev
>
>


-- 
Your ship was destroyed in a monadic eruption.
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to