<div dir="auto" style="font-size:1rem">Hi Jaakko, oh dear you've picked on the most embarrassing part of Haskell.</div><div dir="auto"><br></div><div dir="auto" style="font-size:1rem">> <span style="white-space:pre-wrap;background-color:rgb(255,255,255);font-size:1rem">data Person = Person {name::String, age::Int} deriving Show</span></div><pre style="white-space:pre-wrap;background-color:rgb(255,255,255)"><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">>
> Now, I can create maybe-people like in applicative style:
>
> Person <$> Just "John Doe" <*> Nothing
<br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">Hmm? That returns Nothing -- is that what you expect? Perhaps</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">Person <$> Just "John Doe" <*> Just undefined</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">But why not</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">Just $ Person "John Doe" undefined</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">> The problem with the [applicative] approach</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">> is that it depends on the order of the arguments</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">> because it doesn't utilize the record syntax.</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">You'd think that a leading-edge language like Haskell</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">would have really powerful record abstractions.</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">With ways to avoid the shackles of argument ordering.</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">Then it's sad to admit Haskell's records are feeble.</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">Back in Haskell 98 people were saying "surely we can do better!"</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">Well, essentially nothing's happened.</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">So records are no more than pretty(-ish?) syntax</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">for the ordered arguments style.</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">The label names are not first-class.</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">And field labels for building records only work</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">in very restricted syntactic positions, as you point out:</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">
> I would like to get the benefits of the the record syntax</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">> but with similar code simplicity as the applicative style has.</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">> Do you have ideas is this possible?</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">> My non-working pseudo-code would look like:
>
> Person <$> {name=Just "John Doe", age=Nothing}
>
> But this doesn't work, it's syntax error.
You want that bit in braces to be a free-standing expression.</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">That's called "anonymous/extensible records" (search Haskell wiki).</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">"Anonymous" because it's not tied to any particular datatype.</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">It's self-describing: I am a record with two fields labelled `name, age`;</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">and the order of the labelled fields should be arbitrary.</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">"Extensible" because you could start a record with just one labelled field,</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">and extend it with another labelled field.</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">But I'm not sure what the `Maybe` wrapping is doing for you? I'm going to ignore it.</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">I have some good news and some bad news. There is a Haskell you can do</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">n = (name = "John Doe") -- note round parens</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">n_a = (age = undefined | n) -- | for extend the record</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">p = Person n_a</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">For that you need a slightly different data decl</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">data Person = Person (Rec (name :: String, age :: Int)) deriving Show</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">Round parens again; and a mysterious type constructor.</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">But these records are first-class values.</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">(They're a special variety of tuples.)</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">Perhaps you don't need a datatype?</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">type Person = Rec (name :: String, age :: Int)</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">Then you don't need to apply a data constructor.</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">This style of records is 'Trex' -- Typed Records with extensibility</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><div><a href="https://www.haskell.org/hugs/pages/hugsman/exts.html#sect7.2" target="_blank" style="font-size:1rem">https://www.haskell.org/hugs/pages/hugsman/exts.html#sect7.2</a></div><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">The bad news: Trex is available only in a very old Haskell system,</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">Hugs. So old that its download has bitrotted, see note here</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><div><a href="https://mail.haskell.org/pipermail/hugs-bugs/2018-July/001914.html" target="_blank" style="font-size:1rem">https://mail.haskell.org/pipermail/hugs-bugs/2018-July/001914.html</a></div><br></div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">GHC has had 12 years to come up with something comparable/better.</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">So far, nothing.</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">If you're wanting to get all Applicative and Functorial in GHC,</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">there are heaps of record systems based around Lenses.</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><div><a href="http://hackage.haskell.org/package/lens-tutorial" target="_blank" style="font-size:1rem">http://hackage.haskell.org/package/lens-tutorial</a></div><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">But that's going way beyond Beginners level;</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">you'll need to call on Template Haskell;</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">and probably add some plumbing of your own.</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">(And under the hood you still have ordered arguments;</div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px"> they're rather better encapsulated.)</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div><div dir="auto" style="color:rgb(49,49,49);font-size:1rem;word-spacing:1px">AntC</div><div dir="auto" style="color:rgb(49,49,49);word-spacing:1px"><br></div></pre>