-
Notifications
You must be signed in to change notification settings - Fork 214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UnionType
and UnionInputType
, analogues of RecordType
and RecordInputType
#775
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CI build is failing on GHC 7.10.3 mainly due to needing to import the Semigroup
class
dhall/src/Dhall.hs
Outdated
inputUnion (UnionInputType inputTypeUnion) = InputType makeUnionLit (Union declare) | ||
where | ||
declare = fst <$> inputTypeUnion | ||
makeUnionLit x = fromMaybe (errorWithoutStackTrace unmatched) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to avoid the partial implementation by changing UnionInputType
to:
data UnionInputType a = UnionInputType (Map Text (Expr Src X)) (a -> Maybe (Map Expr Src X))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This representation makes more sense, since we only consume injector in the asum'd form. However, I don't quite see how this can directly help us fix the partiality.
However, this representation gives a hint about how we could make it non-partial; we might be able to write a variant of inputUnion
that gives a fallback option that would be used if anything was Maybe
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
17fd6c3 now incorporates this new representation! It's actually nicer because we get a derivable Contravariant and almost a derivable Monoid instance (waiting for base-4.12, which has Monoid for :*:
).
Still curious about what you had in mind for resolving the partiality issue, though! :)
At work, we are using what I suppose is a simpler variation of this: makeUnion :: Map.InsOrdHashMap LazyText.Text ( Dhall.Type a ) -> Dhall.Type a
makeUnion alts =
let
extract expr = do
Expr.UnionLit ctor v _ <-
return expr
t <-
Map.lookup ctor alts
Dhall.extract t v
expected =
Expr.Union ( Dhall.expected <$> alts )
in Dhall.Type { .. } It looks like yours is the same idea though, and I like not leaking |
@mstksg: I believe you can fix the partiality using a trick similar to In other words, the user interface we supply looks like this: -- I'm not sure if this is the right representation to use, so focus more
-- on the type signatures than the implementation
newtype UnionInputType a = UnionInputType (Map Text (InputType a))
inputConstructorWith :: Text -> InputType a -> UnionInputType a
inputConstructorWith k v = UnionInputType (Data.Map.singleton k v)
inputConstructor :: Inject a => Text -> UnionInputType a
inputConstructor k = inputConstructorWith k inject
instance Contravariant UnionInputType where …
instance Divisible UnionInputType where …
instance Decidable UnionInputType where …
(>|<) :: Decidable f => f a -> f b -> f (Either a b)
(>|<) = Data.Functor.Contravariant.chosen
-- I haven't thought through if this can be implemented. Feel free to
-- change the implementation of `UnionInputType` if this function isn't
-- total
inputUnion :: UnionInputType a -> InputType a
inputUnion = … ... so that the user can write this: injectStatus :: InputType Status
injectStatus =
adapt
>$< inputConstructor "Queued"
>|< inputConstructor "Result"
>|< inputConstructor "Errored"
where
adapt (Queued n) = Left (Left n)
adapt (Result t) = Left (Right t)
adapt (Errored e) = Right e |
A Decidable-inspired interface might work! Although I don't think we could actually use I'll see if I can whip up a "Decidable-inspired" interface (using an analog of |
The Decidable-inspired method (implemented in cc140c3) works and ensures totality! :D However, as feared, it is impossible to actually use
because this would allow the user to construct something silly like a However, dropping in a custom One small note: it's possible to implement I'll still continue to play around with a combined |
@mstksg: Yeah, a monomorphic Also, this branch still needs to import |
New changes should appease GHC 8.0 and above! However, I couldn't get the dependencies to work with GHC 7.10, but I'm not sure if these versions were still officially supported. |
@mstksg: Are you sure your changes don't work with GHC 7.10? CI passed and that requires GHC 7.10 to work The reason Dhall supports GHC 7.10 is for Eta since Dhall is a supported configuration format for Eta packages and Eta is built using GHC 7.10 |
I will go ahead and merge this since CI thinks this is GHC 7.10-ready |
Ah, nice! I couldn't get to the build part, I got stuck in the dependency resolution part. But if it works, then I'll take your word for it :) Thanks! |
Allows us to generate an
Input
for a union:And (potentially partially) create an
InputType
:I couldn't really think of a way to write
inputUnion
in a way that would make sure it was total without a "two-pass" solution, where the user provides the "injecting" logic and the "specify type" logic in two different places; one alternative was a quasi-one-pass system where the user specifies the total logic up-front, but the result can be optionally "validated" by providing a proof of totality before being used. However, that requires encoding the number of branches in the type level, so I'm not sure if the benefit pays for the cost in complexity.Let me know if this isn't something that fits in the vision of the library, or if there's anything I could fix :)