News for hackers. Stuff that matters.
Re:Hindley-Milner Type Inference (2012) by mcphage on Friday July 10, 2020 @04:58PM (#23796378)
> I could not understand why most static language required writing so many types that were easy to deduce and why people where saying that not having to write types made dynamic language better.

In Scala, a lot of libraries end up with deduction-only types—ie, types that can only be deduced, because actually typing out the type signature is very long, complicated, and filled with generics-upon-generics. I don’t find that to be a pleasant outcome—if I can’t fill in the type signature myself, trying to understand what the code is going to do ends up that much more complicated. Yet that’s not an uncommon situation.

Re:Hindley-Milner Type Inference (2012) by The_rationalist on Friday July 10, 2020 @08:12PM (#23798126)
But why the complexity? Most libraries should have "simple" types.
Re:Hindley-Milner Type Inference (2012) by lmm on Friday July 10, 2020 @11:31PM (#23799225)
They mostly do. The cases where you get complex types is where you are using dependent typing. For example, imagine you wanted to write an "update" method. So we have this datatype:

    data Address(line1: String, line2: String, postcode: String)
    data User(name: String, address: Address, phoneNumber: String)
And here's an example of what "update" should do, in JSON:

    // Argument 1
    {
      "name": "Bob",
      "address": {
        "line1": "123 Fake Street",
        "line2": "Beverly Hills",
        "postcode": "90210"
      },
      "phoneNumber": "555-555-5555"
    }
    // Argument 2
    {
      "address": {
        "line1": "377 Fake Street"
      },
      "phoneNumber": "555-555-4444"
    }
    // Result
    {
      "name": "Bob",
      "address": {
        "line1": "377 Fake Street",
        "line2": "Beverly Hills",
        "postcode": "90210"
      },
      "phoneNumber": "555-555-4444"
    }
This kind of function is the kind of thing that keeps people using dynamic languages. It's easy, and obvious, what it should do, and what its type signature is, but in most typed languages you can't write it without constructing a whole parallel hierarchy of datatypes by hand.

Scala is one of about 3 languages where you can actually write this in a nice way and it will be correctly typed. But the type you get will be:

    (User, Field[Label['name], Option[String]] :: Field[Label['address], Option[Field[Label['line1], Option[String]] :: Field[Label['line2], Option[String]] :: Field[Label['postcode], Option[String]] :: HNil]] :: Field[Label['phoneNumber], Option[String]] :: HNil) => User
And until recently it was even worse than that because the compiler didn't know to print the "::" types as infix.

Now with first-class record support in the compiler you could improve this a little bit, but fundamentally there's not really any better way to write that type. Maybe if the language had first-class support for dependent types like Idris you could write ti as `(User, UpdateTo(User)) => User` or something, but the reader would still need a way to find out what `UpdateTo(User)` was concretely. So what do you do?

Re:Hindley-Milner Type Inference (2012) by mcphage on Friday July 10, 2020 @08:36PM (#23798283)
They should, but when the types are all inferred, it’s easier to hide that complexity.