Remix.run Logo
instig007 a day ago

You can do most of it in default Haskell syntax, plus `RecordWildCards`: https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/reco...

sestep a day ago | parent [-]

Oh interesting; is that actually true? I'm not aware of Haskell features that allow it to do better than any of the three other languages I compared to in my post. What would my running example look like in Haskell?

instig007 a day ago | parent [-]

Here's the sample you can play with (interactive: https://play.haskell.org/saved/TWBEYFzH):

  {-# LANGUAGE RecordWildCards #-}


  main =
    transport
      ("2025-09-05T09:00:00Z", "2025-09-05T11:00:00Z")
      foo123
      kwargs
    where
      foo123  = Foo
      kwargs  = Kwargs {..}
      bar     = Bar
      person  = Person {..}
      name    = "Alex Smith"
      phone   = "+1 (555) 555-5555"
      options = Opts {..}
      fragile = True
      window  = PM


  data Foo = Foo
  data Bar = Bar

  data Kwargs = Kwargs
    { bar     :: Bar
    , person  :: Person
    , options :: Opts
    }

  data Person = Person
    { name  :: String
    , phone :: String
    }

  data Opts = Opts
    { fragile :: Bool
    , window  :: HalfDay
    }

  data HalfDay = AM | PM


  transport (start, end)
            foo
            Kwargs { person = Person{ name = who, ..}, options = Opts{..}, ..}
    = do
      doStuff who foo
      moreStuff phone end window
      otherThings start fragile bar


  doStuff who foo               = print "called doStuff"
  moreStuff phone end window    = print "called moreStuff"
  otherThings start fragile bar = print "calle otherThings"
sestep a day ago | parent | next [-]

I see, so similar to the other languages I mentioned in my post, it looks like Haskell doesn't let you colocate the types with the leaves of the binding form?

instig007 10 hours ago | parent [-]

> doesn't let you colocate the types with the leaves of the binding form

Can you elaborate on the effective difference between colocations in your example and this:

  transport Kwargs {person = Person{name = who, ..}, options = Opts{..}, ..}
The `Kwargs{..}` alone does imply a non-ambiguous type in the function signature (without explicit but optional annotations), and it binds locally scoped names too. Why doesn't it colocate in the same sense?
sestep 7 hours ago | parent [-]

It's similar to the Rust example from my post: there are no anonymous records, so in order to be able to construct something with named fields, you need to first define those record types outside. In contrast, my proposed syntax depends on already having anonymous record types like OCaml and TypeScript do, but avoids the extra boilerplate required by separating types from binding forms as shown in my TypeScript example.

instig007 a day ago | parent | prev [-]

To address the example towards the end of your post, if you want patterns + struct binding at the same time, prefix patterns with `bindName@`, for instance:

  transport
    myTuple@(start, end)
    foo
    kwargs@(Kwargs { person = Person{ name = who, ..}, options = Opts{..}, ..})
  = do
      ...