target / row-types Goto Github PK
View Code? Open in Web Editor NEWA Haskell library for open records and variants using closed type families and type literals
License: MIT License
A Haskell library for open records and variants using closed type families and type literals
License: MIT License
Steps to reproduce:
> r = #a .== "a" .+ #b .== "b"
> r
#a .== "a" .+ #b .== "b"
> [r]
[#a .== "a"] .+ ]#b .== "b"]
> [r,r]
[#a .== "a",#a .== "a"] .+ ]#b .== "b"] .+ ,#a .== "a"] .+ ]#b .== "b"]#b .== "b",#a .== "a"] .+ ]#b .== "b"]
> [r,r,r]
[#a .== "a",#a .== "a",#a .== "a"] .+ ]#b .== "b"] .+ ,#a .== "a"] .+ ]#b .== "b"]#b .== "b",#a .== "a"] .+ ]#b .== "b"] .+ ,#a .== "a",#a .== "a"] .+ ]#b .== "b"] .+ ,#a .== "a"] .+ ]#b .== "b"]#b .== "b",#a .== "a"] .+ ]#b .== "b"]#b .== "b",#a .== "a",#a .== "a"] .+ ]#b .== "b"] .+ ,#a .== "a"] .+ ]#b .== "b"]#b .== "b",#a .== "a"] .+ ]#b .== "b"]
Why trial
function put successful result into Left instead of Right?
Wouldn't be Right more convenient because of e.g. default Monad instance?
(#x .== 4 :: Subset ("x" .== Integer) t => Rec t) .! #x
• Could not deduce: t1 ~ 'R '[ "x" ':-> Integer]
from the context: Subset ('R '[ "x" ':-> Integer]) t
bound by the inferred type of
it :: Subset ('R '[ "x" ':-> Integer]) t => Rec t
at <interactive>:12:1-49
or from: Subset ("x" .== Integer) t1
bound by an expression type signature:
forall (t1 :: Row *). Subset ("x" .== Integer) t1 => Rec t1
at <interactive>:12:14-48
‘t1’ is a rigid type variable bound by
an expression type signature:
forall (t1 :: Row *). Subset ("x" .== Integer) t1 => Rec t1
at <interactive>:12:14-48
Expected type: Rec t1
Actual type: Rec ("x" .== Integer)
• In the expression:
(#x .== 4 :: Subset ("x" .== Integer) t => Rec t)
In an equation for ‘it’:
it = (#x .== 4 :: Subset ("x" .== Integer) t => Rec t)
But
(#x .== 4 :: (Subset ("x" .== Integer) t, t ~ ("x" .== Integer)) => Rec t) .! #x
4
Quite late to the party, but it is about time I upgrade to row-types-1.0
I tried to do it, including some cargo-culting around metamorph
, but now the test suite segfaults…
To reproduce, run cabal run test
in this commit
nomeata/haskell-candid@aeb1bce (part of branch row-type-1.0
).
Did I do something stupid when changing metamorph? Or am I somewhere else relying on internals of row-types that have changed?
Probably the issue isn’t with your code, but thanks for your help nevertheless.
At the moment it does not build:
src/Data/Row/Aeson.hs:29:21: error:
• Couldn't match type: unordered-containers-0.2.19.1:Data.HashMap.Internal.HashMap
s0 Value
with: Data.Aeson.KeyMap.KeyMap Value
Expected: Rec r -> Object
Actual: Rec r
-> unordered-containers-0.2.19.1:Data.HashMap.Internal.HashMap
s0 Value
• In the second argument of ‘(.)’, namely
‘Rec.eraseToHashMap @ToJSON toJSON’
In the expression: Object . Rec.eraseToHashMap @ToJSON toJSON
In an equation for ‘toJSON’:
toJSON = Object . Rec.eraseToHashMap @ToJSON toJSON
|
29 | toJSON = Object . Rec.eraseToHashMap @ToJSON toJSON
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/Data/Row/Aeson.hs:36:59: error:
• Couldn't match expected type ‘Key’ with actual type ‘Text’
• In the second argument of ‘(.:)’, namely ‘(show' l)’
In a stmt of a 'do' block: x <- o .: (show' l)
In the expression:
do x <- o .: (show' l)
x `seq` pure x
|
36 | r <- Rec.fromLabelsA @FromJSON $ \ l -> do x <- o .: (show' l)
| ^^^^^^^
src/Data/Row/Aeson.hs:48:66: error:
• Couldn't match expected type ‘Key’ with actual type ‘Text’
• In the second argument of ‘(.:)’, namely ‘(show' l)’
In the expression: o .: (show' l)
In the second argument of ‘($)’, namely ‘\ l -> o .: (show' l)’
|
48 | parseJSON (Object o) = Var.fromLabels @FromJSON $ \ l -> o .: (show' l)
| ^^^^^^^
To any users of row-types, I'm playing around with some breaking changes and am looking for feedback. The changes are breaking enough that I'm planning on releasing the next version as 1.0.0.0
so anyone with any limits on forward-compatibility won't have a big problem, but I'd still value users' opinions.
I have four basic questions:
Have you ever used Forall
or metamorph
in your code?
Have you ever used the unsafe
record or variant functions outside of a call to metamorph
?
Have you run into issues where GHC seemed really stupid about constraints (where you needed to add a seemingly obvious constraint like Extend l t r .! l ≈ t
)? If so, do you have any examples?
Do you think it's silly that trial
, multiTrial
, and split
(all of which return an Either) all put the "successful" result in Left
and the failure in Right
?
Any type family to .+
Rec's, not Row's only?
(Or to get Row
type of Rec
type)
In particular it'd be nice to be able to derive Map f r .! l ~ f t
from r .! l ~ t
, where r
is polymorphic. It seems like there is no easy way to achieve this now, or am I missing something?
To all concerned, this repository is no longer being actively maintained at this site. The new source of truth for row-types
can be found at https://github.com/dwincort/row-types. Please post issues and submit PRs there from now on.
It's mentioned in the examples readme, but I can't find it https://raw.githubusercontent.com/target/row-types/master/examples/Examples.lhs
I hope this is an okay place to ask a question.
Basically, if I have a row type, say, "a" .== Foo x .+ "b" .== Bar x
, and Foo and Bar are both Functors (or any class, really), is there an easy way to map over the entire structure and get a result of "a" .== Foo y .+ "b" .== Bar y
?
I've been trying to use map
and transform
, but have had no success using them so far (my type-level experience is limited).
Thanks in advance!
When generating instances, aeson
can be configured to omit Nothing
fields. At the moment the instances for Rec
don't do this: Nothing
gets serialized as null
and you can't omit such fields in the JSON. It would be nice to have a way to express records with fields that can be missing.
I don't really know what to do about this: both seem sensible, and in aeson
this is configurable, and arguably it's a bit weird to treat Maybe
specially like this, see: haskell/aeson#646
Can you please publish row-types-aeson
and row-types-barbies
?
I noticed that many of the type families for Data.Row.Internal
only operate on rows of kind Row *
, but it seems like it would be just as useful to use these type families (in particular, (.==)
and (.+)
) for rows of any kind, since row types can be used for more than just records and variants.
I have a working version here:
https://github.com/jqyu/graphql-row-types/blob/master/src/Data/Row/Poly.hs
and I would be happy to make a PR if you think this is the right approach (:
This repository will be archived in 30 days in accordance with Target's internal retention policy.
Archived projects become read-only and will remain accessible to the public.
If you have questions or concerns, reach out here or internally to the OSPO team.
For example, does compile time suffer exponentially, having ~ 1+ minute builds past 8-10 fields similar to turingjump/bookkeeper#13 and agrafix/superrecord#12? Or has row-types
managed to avoid that particular issue?
If one of you are willing, I'd love to read a comprehensive comparison to some other approaches to find out the strengths and limitations of this implementation. The most efficient way I know how to compare to most other packages at once is to fill in cells in this Google Sheet.
I've added row-types
at row 33, under the section titled "Looking for reports:".
Is one of you up for filling in some cells there? Maybe @strake, @atzeus, @dwincort, or someone else?
p.s.: I've heard of this package from this talk. Some more background can be gleaned from this reddit thread.
I am playing around with row-types
; neat work.
I want to connect it to some other generic library (not shared yet), but I am facing a wrinkle. ToNativeExact t ρ
is a type class. I believe I could really use a type family that goes from the generic Rep t
type to a Row r
. Would that be possible?
I am running in a problem. I want to write this code:
instance CandidRow r => Candid (V.Var r)
instance CandidRow r => CandidVal (V.Var r) where
asType = VariantT $ fieldOfRow @r
toCandidVal' v = VariantV (unescapeFieldName t) val
where (t, val) = V.eraseWithLabels @Candid toCandidVal v
fromCandidVal' (VariantV f v) = do
needle <-
V.fromLabels @Candid $ \l -> do
guard (f == unescapeFieldName (R.toKey l))
return $ fromCandidVal v
<|> Left ("Unexpected variant tag " ++ show (pretty f))
V.sequence needle
fromCandidVal' v = Left $ "Unexpected " ++ show (pretty v)
The point is that I want V.fromLabels
to use the Alternative
instance of Either String
to pick the right field (based on the f
). But I want to avoid decoding failures within fromCandidVal
to cause backtracking here!
So inside fromLabels
I return the pure fromCandidVal v
, and only after the right label was found, I want to perform that action. This calls for V.sequence
, it seems.
But now I get
• Could not deduce: AllUniqueLabels (V.Map (Either String) r)
arising from a use of ‘V.fromLabels’
from the context: CandidRow r
where
type CandidRow r = (Typeable r, AllUniqueLabels r, Forall r Candid)
It seems that AllUniqueLabels r
does not imply AllUniqueLabels (V.Map f r)
… is there a way to get that?
…
Ah, it seems that there is fromLabelsMapA
for records, but not for variants. Is there a deep reason for that?
I'd like to request help for designing a solution I'm building for integration test factories together with row-types.
Here's a self-containing repo which can be built/launched via stack run
https://github.com/k-bx/row-types-default/blob/e6a2b5c03d419038d3fb5301251c2aca71f72d63/src/Main.hs
The two problems I'm trying to solve now:
First, how do I make ability to make parameters implicit with default value to be Nothing
? Instead of calling buildProduct (#name .== Nothing .+ #companyId .== Nothing)
I'd like to only be required to mention those parameters which are non-Nothing (which I want to over-write from default).
Second, what would be a good way to pass parameters of buildCompany
to buildProduct
under a name #company
? E.g., I'd like my API to look like this at the end:
main = do
product' <- buildProduct (def (#company .== def (#name .== "My Company")))
...
and this would build everything with default values, except for product's company name to be "My Company"
.
Hope this sounds clear. Thanks!
Would it make sense to have not-tagged sums (like).
Also pls consider to use .*
instead of .+
(in way like Caml using *
in types) for records, and keep .+
for variants/unions.
Hi, ready for a new release to hackage? examples don't compile with 0.3.0.0
Thanks!
I've been reading the Example.hs file, and want to share some quick thoughts. This is a low priority ticket on my part, feel free to only respond to this days or weeks from now at your leisure. I'm writing now because I don't want to forget about it.
So, reading this section:
get2D'' :: (r ≈ "x" .== Double .+ "y" .== Double, Disjoint r rest)
=> Rec (r .+ rest)
-> Rec r
get2D'' ((Label :: Label "x") :== n1 :+ (Label :: Label "y") :== n2 :+ _)
= #x .== n1 .+ #y .== n2
It would indeed be much nicer if we could just write:
get2D'' :: (r ≈ "x" .== Double .+ "y" .== Double, Disjoint r rest)
=> Rec (r .+ rest)
-> Rec r
get2D'' (#x :== n1 :+ #y :== n2 :+ _)
= #x .== n1 .+ #y .== n2
Trying to do this now, we get:
> :t \(#a) -> 1
<interactive>:1:3: error: Parse error in pattern: #a
A parse error. So, it might be quite trivial to fix this upstream in GHC's parser, just make #a
de-sugar to (Label :: Label "a")
in a pattern context as well. And I am guessing/hoping/wondering that GHC folks would be very happy to take this contribution. I've briefly looked if there may be a trac ticket even open about this, but I haven't found any yet. So maybe the only reason this isn't working is because no one was inconvenienced by it enough to fix it or raise it.
What do you think?
With row-types it's possible to pass some named parameters to function.
But what about partial application? Would it make sense to implement .->
type indexed by parameter name? "Int .-> "x" Float .-> "y" ()
(Or? ("x", Int) .-> ("y", Float) .-> ()
)
Additional feature: optional parameters.
E.g. via some typeclass mark some field as optional, wrap them to Maybe
if missed.
Optional '["x"] => Rec ("x" .== Int .+ "y" .== Float) -> ()
. Though not sure here. It must behave like Rec ("y" .== Float) -> ()
for caller, and Rec ("x" .== Maybe Int .+ "y" .== Float) -> ()
for function implementation body.
"Int .?> "x" Float .-> "y" ()
(Or? ("x", Int) .?> ("y", Float) .-> ()
)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.