Skip to content

Conversation

@justinwoo
Copy link
Contributor

@justinwoo justinwoo commented Jun 24, 2017

fixes #25

uses some flags to determine casing and then uses these flags in encoding/decoding

updated excerpt:

testOption (makeCasingOptions toUpper) "\"FrIkAnDeL\"" Frikandel
testOption (makeCasingOptions toLower) "\"FrIkAnDeL\"" Frikandel

@justinwoo justinwoo force-pushed the unary-constructor-literal branch 3 times, most recently from db4dee6 to 8a41b83 Compare June 26, 2017 17:24
@justinwoo
Copy link
Contributor Author

Alternatively, I wrote this up where I've defined a function to provide instances specifically for sum types of unary constructors: justinwoo@179831c. Should I squash this here instead of using the conditional version in this branch?

I'd really like to also provide some Fail constrained instances for warnings and explanations, but I don't know how to do that without having overlapped instances warnings in usage sites.

@paf31
Copy link
Owner

paf31 commented Jun 27, 2017

What do you think about making a separate generic decoding/encoding function for enums like this? That way we could actually enforce using the type system that they only accept "enum types".

@justinwoo justinwoo force-pushed the unary-constructor-literal branch from 8a41b83 to 73155eb Compare June 27, 2017 15:44
@justinwoo
Copy link
Contributor Author

I squashed my separate genericDecodeUnaryConstructors and genericEncodeUnaryConstructors functions into this one. Like my comment before though, while it doesn't match any instances for reps that aren't Sum or Constructor NoArg, I can't add Fail constraints without having overlapping instance warnings, so it could be a little confusing to use. But that fail constraint can wait until something with instance chains gets figured out.

@@ -0,0 +1,62 @@
module SumEncoding where
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Module name is incomplete here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, oops

=> GenericDecodeUnarySum (Constructor name NoArguments) where
decodeSum {constructorTagTransform} f = do
tag <- constructorTagTransform <$> readString f
unless (constructorTagTransform tag == ctorName) $
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You apply constructorTagTransform twice.

fail (ForeignError ("Expected " <> show ctorName <> " tag for unary constructor literal " <> ctorName))
pure $ Constructor NoArguments
where
ctorName = constructorTagTransform $ reflectSymbol (SProxy :: SProxy name)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here

@paf31
Copy link
Owner

paf31 commented Jun 27, 2017

Just add a Fail instance for Product and Rec?

Also, can we use the term "enum"? I think it's pretty common for this type of data.

@justinwoo justinwoo force-pushed the unary-constructor-literal branch from 73155eb to 67c61e5 Compare June 27, 2017 16:49
@justinwoo
Copy link
Contributor Author

Updated. I added the instances, though, I haven't been able to come up with ways to reach those without a constructor constraint.

@justinwoo justinwoo force-pushed the unary-constructor-literal branch from 67c61e5 to 321dd09 Compare June 27, 2017 16:53
@paf31
Copy link
Owner

paf31 commented Jun 27, 2017

Yes, you would need to write several instances for Constructor, but they won't overlap.

encodeEnum _ _ = unsafeCrashWith "unreachable encodeEnum was reached."

instance recGenericEncodeEnum
:: Fail """
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe pull the error messages out into a single common type synonym?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I wouldn't be able to change the wording right? I do want to put what kind of type they were trying to plug in here for a more relevant error message

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just say "doesn't work with constructors with arguments" though? Records and products are both types of arguments. Do you not think it's clear enough?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that's fine. I'll switch them over then

@paf31
Copy link
Owner

paf31 commented Jun 27, 2017

Another option is to use TypeEquals.

@justinwoo justinwoo force-pushed the unary-constructor-literal branch 2 times, most recently from 8bd5849 to 78bf86d Compare June 27, 2017 17:07
{ sumEncoding :: SumEncoding
, unwrapSingleConstructors :: Boolean
, unwrapSingleArguments :: Boolean
, constructorTagTransform :: String -> String
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this go into TaggedObject?

decodeEnum opts f = Inl <$> decodeEnum opts f <|> Inr <$> decodeEnum opts f

instance ctorNoArgsGenericDecodeEnum
:: (IsSymbol name)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parens are redundant here.

@justinwoo justinwoo force-pushed the unary-constructor-literal branch 2 times, most recently from f8c910b to eef91d7 Compare June 27, 2017 17:41
@justinwoo
Copy link
Contributor Author

Updated this. Like we found on Slack, I couldn't find out how to make a synonym actually work at the usage site of the Fail instances, and then I moved the tag transform into SumEncoding.


instance ctorArgumentGenericEncodeEnum
:: Fail """
genericEncodeEnum cannot be used with constructors with arguments, as it is meant to work with string literal "Enums", Sum types of no-argument constructors.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would still trim this down a bit and put the stuff about enums into the documentation for the classes.

@justinwoo justinwoo force-pushed the unary-constructor-literal branch from 07e68b7 to 0dc8f05 Compare June 27, 2017 18:49
@justinwoo
Copy link
Contributor Author

Wrote up some docstrings with a small code example in each top level method, with just short descriptions of the typeclasses and the instance errors.

=> GenericDecodeEnum (Constructor name NoArguments) where
decodeEnum {sumEncoding: TaggedObject {constructorTagTransform}} f = do
tag <- readString f
unless (constructorTagTransform tag == ctorName) $
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong way around here, surely?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, yeah. the ctorname is already transformed, but i guess transforming the tag itself is kinda wonky...

ctorName = constructorTagTransform $ reflectSymbol (SProxy :: SProxy name)

instance ctorArgumentGenericDecodeEnum
:: Fail """
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put these Fail constraints on one line and just use a single error message in a type declaration.

:: forall a rep
. Generic a rep
=> GenericDecodeEnum rep
=> Options
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're only using constructorTagTransform here, let's only require a record with that one field.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use row polymorphism if we want to support more fields.

@paf31
Copy link
Owner

paf31 commented Jul 6, 2017

Sorry for the delay, I have a few more comments.

@justinwoo justinwoo force-pushed the unary-constructor-literal branch from 0dc8f05 to b69b255 Compare July 6, 2017 22:10
@justinwoo
Copy link
Contributor Author

I updated this, but I still cannot get the type alias string to properly work on my machine for the Fail constraint. I will get "No type class instance was found for Fail GenericEncodeDecodeFailMessage"...

@paf31
Copy link
Owner

paf31 commented Jul 6, 2017

Ok, I'd prefer one of the following then:

  1. No Fail instances for now
  2. Just repeating the same error message in the code, but on single lines.
  3. Adding a helper class with a single instance so that we can put the error in a single place.

Adds constructor tag transform so that users can customize the tag as
needed
@justinwoo justinwoo force-pushed the unary-constructor-literal branch from b69b255 to e42b38a Compare July 6, 2017 23:05
@justinwoo
Copy link
Contributor Author

Pushed an update to do no 2. I'll try to remember to come back to this when we get purescript/purescript#2972 fixed.

@paf31 paf31 merged commit 34332d8 into paf31:master Jul 6, 2017
@paf31
Copy link
Owner

paf31 commented Jul 6, 2017

Great, thanks for all the work on this!

"purescript-symbols": "^3.0.0"
"purescript-proxy": "^2.1.0",
"purescript-symbols": "^3.0.0",
"purescript-strings": "^3.2.1"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like you're using this any more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😨

@justinwoo
Copy link
Contributor Author

Thanks!!! Now I need to remember to update my howto guides and start making some noise about enum sum type support 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Option for encoding sum types as insensitive strings?

2 participants