Re: [Haskell-cafe] Extensible records & mandatory/optional record fields

On Tue, 14 Feb 2017 at 18:50, Harendra Kumar said:
In my application, I want some of the fields in a record to have default values while others must always be specified by the user. I can implement this using the rawr records library (http://hackage.haskell.org/package/rawr)
Hi Harendra. I believe rawr builds on some of the work in 'overloaded records'. That's a suite of features being developed right now look here for what's coming soon https://github.com/adamgundry/ghc-proposals/blob/overloaded-record-fields/pr...
like so:
def :: ("b" := String) -> R ("a" := Int, "b" := String) def t = (R (#a := 0) :*: R t) -- merge with defaults
let r = def (#b := "hello")
That looks like some sort of anonymous/extensible records system. What is data constructor `R`; where is it defined? There's a few mentions of 'anonymous' records on that link above. (And mention of rawr.) It's not clear what you're trying to do. Do you need anonymous/extensible records? Why use `let` to bind a value for `r`?
Here field "a" has a default value (i.e. it is optional when "def" is used) but field "b" does not have a default value and has to be explicitly specified by the user. This is made possible by record merging feature of rawr, making the record extensible.
I could not find an equivalent way of achieving this using overloaded records (http://hackage.haskell.org/package/overloaded-records).
So far, overloaded records is based on standard-ish Haskell record decls. So you must declare a distinct record constructor and field labels. Like data MyR = MyR { a :: Int, b :: String }; If you want default values: myRdef = MyR{ a = 0 }; -- don't have to give b Then bind some value, to incorp defaults. r = myRdef { b = "hello" }; -- takes the defult for a
Is record merging possible or can be made possible
using overloaded-records or with the ghc overloaded records poposal? If not, is there a plan to make something like this
It looks to me like you don't need '"record merging". What do you think it is; why do you think you need it? possible in future? I'd say it's on the radar, but a long way off.
Or will this never be possible with the in built record syntax?
Note that, this is handy to simulate mandatory and
I think that built-in record syntax will fit your requirements. optional keyword
arguments to a function by passing them in the form of a record.
Something which is available in other languages like
Sure. Keyword arguments to a function are fixed. No need for building dynamic/anonymous structures. Yes it's good (and standard practice) to pass as a record. So you can use a standard built-in Haskell record decl, as I used above. python. It looks to me that you're trying to write Python code in Haskell. Not a good idea. Use built-in/static features first. Think about the difference between a compiled vs interpreted language. Only when static features really really aren't working, consider dynamic/extensible. AntC

Hi Anthony,
Please see my comments below.
On 16 February 2017 at 02:31, Anthony Clayden
On Tue, 14 Feb 2017 at 18:50, Harendra Kumar said:
Hi Harendra. I believe rawr builds on some of the work in 'overloaded records'.
I am aware of the ghc "overloaded records" proposal. rawr provides anonymous extensible records using the overloaded labels feature of ghc 8. Records can be merged or partitioned. I believe, the key difference between "overloaded records" and rawr is that the latter provides extensible records while the former does not. Though overloaded records can match a record based on the fields it contains.
It's not clear what you're trying to do. Do you need anonymous/extensible records?
I am trying to write a program which provides a friendly high level DSL to the user. I want a pure function like API but instead of passing positional parameters I want the user to be able to specify arguments based on keywords and be able to skip any optional arguments. Something like the following, name is mandatory and email is optional: maintainer (#name := "Harendra Kumar", #email := "xyz@gmail.com") I can achieve this using rawr. The argument to the function is an anonymous record and we can pattern match partially using the mandatory fields in the record to statically check that those fields are present. The optional fields are then supplied by applying the user supplied record on a default record. Here is a full working program for this example (you will need the latest rawr from github): {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE ScopedTypeVariables#-} {-# LANGUAGE TypeOperators#-} import Data.Rawr pr t = print $ case (R t) of r@(P (_ := name :: "name" := String)) -> R (#email := " default@gmail.com") :<= r main = do -- both name and email are specified by the user. pr (#name := "Harendra Kumar", #email := "xyz@gmail.com") -- only name is supplied by the user, the default value of the optional field "email" will be used pr (#name := "Harendra Kumar") -- This will not compile since name is a mandatory field -- pr (#email := "xyz@gmail.com") I am pretty sure that I am not writing python code in Haskell I was only trying to say that this is a pretty useful feature in python and I guess in some other imperative languages too. It allows you to write self documenting code where necessary. It will be nice if we have a way to achieve something like this.
Like
data MyR = MyR { a :: Int, b :: String };
If you want default values:
myRdef = MyR{ a = 0 }; -- don't have to give b
Then bind some value, to incorp defaults.
r = myRdef { b = "hello" }; -- takes the defult for a
This is the first approach that I tried, this is commonly used in many libraries. The only drawback with this is that I cannot enforce mandatory/optional fields statically. All fields are optional in this case. -harendra
participants (2)
-
Anthony Clayden
-
Harendra Kumar