Open heptahedron opened 6 years ago
I agree that construction is annoyingly awkward. I use variadic functions in a couple projects and I'm not against them, but nor am I totally in love. The typical drawback is that you need to write a lot of types, but perhaps that wouldn't be much of a change for most uses of vinyl.
Can you take a look at adding some unit test examples and/or updating existing tests to use the builder to make sure it slots in without friction? If everything is working, I'd be tempted to add this as a function named vinyl
. In particular, let's make sure one can write, vinyl (#name =: "joe") (#age =: 99)
as building ElField
records is brutally noisy with all those symbols.
yeah, I don't like polyvariadic functions either, and we need test cases (/ examples) that infer correctly (without annotations). also
1) shorter aliases for (:&) and RNil can help. e.g.
(#name =: "joe") ^ (#age =: 99) ^ nil
as well as aliases for grouping record-cons with a constructor/destructor of commonly used functors. like Identity, Const (when converting to/from), ElField (as above), Lazy versus the default strict, Compose, etc. patterns give us constructors that can be matched on too.
e.g.
1 :* 2 :* 3 :* Z
-- inferred:
-- :: (Num a, Num b, Num c) => Rec Identity [a,b,c]
given:
pattern (:*) :: a -> Rec I as -> Rec I (a ': as)
pattern (:*) x xs = I x :& xs
infixr 7 :*
pattern Z :: forall (f :: k -> *). Rec f '[]
pattern Z = RNil
pattern (:#) :: forall a (b :: k) (bs :: [k]). a -> Rec (C a) bs -> Rec (C
a) (b ': bs)
pattern (:#) x xs = C x :& xs
infixr 7 :#
...
see https://github.com/sboosali/export/blob/master/sources/Export/Vinyl.hs#L49
and, identity function helpers for specializing overloaded literals; like
the default-ly overloaded integers, and the commonly overloaded strings.
since, depending on how generic the functions consuming an overloaded
record are, you'll get type defaulting and type errors (like from print
)
e.g.
int :: Int -> Identity Int
text :: Text -> Identity Text
int 1 :& text "hello" :& nil
or
pattern Int :: Int -> Identity Int
pattern Text :: Text -> Identity Text
for pattern matching too, as above.
2) imo, the sugar of a method that is overloaded over tuples of any size is cleaner than overloading on arity (i.e. an "uncurried" version of your "vinyl" method).
e.g.
record (#name =: "joe", #age =: 99)
as pseudo-OverloadedTuples. related: https://github.com/sboosali/export/blob/master/sources/Export/Curry.hs#L16
the benefit to this is that syntactically, tuples are more obviously related to records, and more impor/tantly, inference is better.
Or, given a module that instantiates labels as Field
constructors rather
than Proxy
, which has a Clojure-like look. e.g.
record
( #name "joe"
, #age 99
)
we can specialize the record
method above to ElField
, or keep it
general to n-tuples of any functor. I can draw this out tomorrow.
so anyways, I strongly agree with vinyl needing better "officially
recommended" syntax, but I wanted to propose some alternatives to
polyvariadic functions (which again, are hard to read and cause inference
problems for me, whenever I use them, iirc format
and sh
).
On Wed, Feb 21, 2018 at 7:12 PM, Anthony Cowley notifications@github.com wrote:
I agree that construction is annoyingly awkward. I use variadic functions in a couple projects and I'm not against them, but nor am I totally in love. The typical drawback is that you need to write a lot of types, but perhaps that wouldn't be much of a change for most uses of vinyl.
Can you take a look at adding some unit test examples and/or updating existing tests to use the builder to make sure it slots in without friction? If everything is working, I'd be tempted to add this as a function named vinyl. In particular, let's make sure one can write, vinyl (#name =: "joe") (#age =: 99) as building ElField records is brutally noisy with all those symbols.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/VinylRecords/Vinyl/issues/111#issuecomment-367553869, or mute the thread https://github.com/notifications/unsubscribe-auth/ACNoMXwCC-PMtxfFeKA3gjYKnknPY6P0ks5tXNsOgaJpZM4SOqVF .
--
(this message was composed with dictation: charitably interpret typos)Sam Boosalis
Those are good suggestions to think about, @sboosali, thanks for bringing them up! Personally, I'm weakly negative on more operators as I have trouble keeping them straight in my memory. I also wouldn't want to shadow (^)
from Prelude
.
I used to be more concerned about the functor zoo with vinyl
, but, for myself, where I really want the concise syntax is always Identity
. I don't know how representative that experience is, but when I want Const
or Maybe
or anything less common, I'm fine with writing it out because it's probably worth drawing attention to the deviation from the far more common (for me) use of Identity
.
I'd also be fine with the uncurried approach, and that (#name "joe", #age 99)
syntax is striking me as quite appealing. Does that really fit into things cleanly?
I agree about being explicit about the functors, and I use Compose and ElField myself more (than those I listed).
And, I wasn't actually suggesting shadowing anything from prelude :-), just that a one-char thing looks nicer (like #, etc).
[Tuple syntax]
I think I did it when ghc8 came out, but I can find it or double check. You create a IsLabel instance for ElField constructors (which shadows other similar syntax hacks that instantiate IsLabel for ((->) a)).
It's not clean in that: the field sugar either requires overlapping instances, aggressively exporting the instance, or (my preference) just adding an orphan instance for people to explicitly voluntarily import; and the tuple sugar itself requires an arbitrary (finite) maximum tuple size supported.
Anyways, let me try it out (sorry for the delay, I was going to do it this weekend).
On Feb 26, 2018 6:36 PM, "Anthony Cowley" notifications@github.com wrote:
Those are good suggestions to think about, @sboosali https://github.com/sboosali, thanks for bringing them up! Personally, I'm weakly negative on more operators as I have trouble keeping them straight in my memory. I also wouldn't want to shadow (^) from Prelude.
I used to be more concerned about the functor zoo with vinyl, but, for myself, where I really want the concise syntax is always Identity. I don't know how representative that experience is, but when I want Const or Maybe or anything less common, I'm fine with writing it out because it's probably worth drawing attention to the deviation from the far more common (for me) use of Identity.
I'd also be fine with the uncurried approach, and that (#name "joe", #age 99) syntax is striking me as quite appealing. Does that really fit into things cleanly?
— You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/VinylRecords/Vinyl/issues/111#issuecomment-368726578, or mute the thread https://github.com/notifications/unsubscribe-auth/ACNoMdbbpQxafr7IFvH4cvMfJL_pPwb5ks5tY2o7gaJpZM4SOqVF .
I took a look at the
HList
lib, which I had heard contained some polyvariadic constructors, because I thought they would significantly help with Vinyl, where currently construction is fairly verbose (since all fields must be wrapped in some data constructor in addition to the noise brought about from:&
andRNil
).Here's my first crack at it, is this something that would be accepted if I were to make a pull request?
https://gist.github.com/heptahedron/45c188e7528d9438ec9ae56ecaecd6ec