Skip to content
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

Refactor syntax/type level programming to YesNo #151

Merged
merged 1 commit into from
Nov 24, 2018
Merged

Refactor syntax/type level programming to YesNo #151

merged 1 commit into from
Nov 24, 2018

Conversation

razcore-rad
Copy link
Contributor

@razcore-rad razcore-rad commented Nov 21, 2018

(Added by Jordan): This change was introduced due to discussion in #139

Copy link
Owner

@JordanMartinez JordanMartinez left a comment

Choose a reason for hiding this comment

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

Thanks for getting to this so quickly.

A few things should be renamed to better distinguish the value-level and type-level instances. There's also a few instance names that need to be renamed. Other than that, it looks good.


foreign import kind Boolean
foreign import kind YesNo
Copy link
Owner

Choose a reason for hiding this comment

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

The way this is defined, it's hard to see the difference between then YesNo type and the YesNo kind. Elsewhere in this PR, you use YesNoKind, which is correct and which I'd prefer.

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 would say that this change should then propagate throughout and then we should have

foreign import kind YesNoKind

foreign import data YesK :: YesNoKind
foreign import data NoK :: YesNoKind

as well, shouldn't we? Otherwise the Yes/No might get confused with the value-level instances

Copy link
Owner

Choose a reason for hiding this comment

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

I replied to your later comment, but stating it again here: yes, let's do it that way.

@@ -19,11 +19,11 @@ foreign import data Value_Level_Instance2 :: Value_Level_Type_Kind
-- despite the "foreign import" syntax!
----------------------

-- Using the value-level type Boolean as an example...
data Boolean_ = True_Value | False_Value
-- Using a Boolean-like value-level type as an example...
Copy link
Owner

Choose a reason for hiding this comment

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

I like that you have referred to Boolean here as the analogy of YesNo. However, it will likely make others wonder why Boolean itself wasn't just used, leading them to open a new issue.

Perhaps this comment should include a link to the corresponding issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason I don't think it would be too problematic is that you already talk about the fact that Boolean is an internal type and you change slightly the names in some places so there's no overlap. But sure, once we get the Boolean info written it won't hurt to have a link

foreign import data True :: Boolean
foreign import data False :: Boolean
foreign import data Yes :: YesNo
foreign import data No :: YesNo
Copy link
Owner

Choose a reason for hiding this comment

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

This no longer distinguishes the instance (e.g. data YesNo = Yes) from the type (e.g. kind YesNoKind = Yes).

Perhaps we should distinguish it like this...?

data YesNo = Yes_Value | No_Value

foreign import kind YesNoKind
foreign import data Yes :: YesNoKind
foreign import data No :: YesNoKind

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How about going with

data YesNo = Yes | No

foreign import kind YesNoKind
foreign import data YesK :: YesNoKind
foreign import data NoK :: YesNoKind

like I mentioned in the first comment?

Copy link
Owner

Choose a reason for hiding this comment

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

Yes, that sounds good.

instance toInt_FalseZero :: ToInt False Zero
class ToInt (input :: YesNo) (output :: ZeroOrOne) | input -> output
instance toInt_TrueOne :: ToInt Yes One
instance toInt_FalseZero :: ToInt No Zero
Copy link
Owner

Choose a reason for hiding this comment

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

These instances should be renamed to toInt_YesOne and toInt_NoZero

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, missed these

foreign import kind YesNoKind
foreign import data Yes :: YesNoKind
foreign import data No :: YesNoKind
data YesNoProxy (a :: YesNoKind) = YesNoProxyInstance
Copy link
Owner

Choose a reason for hiding this comment

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

(I'm including this comment in case the question comes to mind due to other renaming comments in this review)

This could be renamed to YesNoKindProxy, but I think that's unnecessary. So, I think this should be left as you have it now.

@razcore-rad
Copy link
Contributor Author

razcore-rad commented Nov 22, 2018

Amended the commit to include changes we discussed, hope I didn't miss any line, if you see something missing let me know.

closes #152

edit
the extra amends are for little fixes like changing YesNoK in one sole instance to YesNoKind etc.

Copy link
Owner

@JordanMartinez JordanMartinez left a comment

Choose a reason for hiding this comment

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

Looks like you missed two things. Just push another commit that fixes that. No need to clean up the commit history since I can squash the commit into one.

foreign import data False :: BooleanKind
foreign import kind YesNoKind
foreign import data Yes :: YesNoKind
foreign import data No :: YesNoKind
Copy link
Owner

Choose a reason for hiding this comment

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

Looks like you forgot to use the same name scheme (YesK/NoK)

falseK :: BooleanProxy False
falseK = BooleanProxyInstance
noK :: YesNoProxy No
noK = YesNoProxyInstance
Copy link
Owner

Choose a reason for hiding this comment

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

and update the YesNoProxy [Yes/No] to [YesK/NoK] here, too.

@razcore-rad
Copy link
Contributor Author

razcore-rad commented Nov 24, 2018

While applying the last fixes I found out that the example with toRed/toBlue doesn't work:

> :p
… toRed :: YesNoProxy YesK -> String
… toRed _ = "red"
…
> reifyYesNo Yes toRed
Error found:
in module $PSCI
at  line 1, column 16 - line 1, column 16

  Could not match type

    b0

  with type

    YesK


while trying to match type YesNoProxy b0
  with type YesNoProxy YesK
while checking that expression toRed
  has type YesNoProxy b0 -> t1
in value declaration it

where b0 is a rigid type variable
        bound at line 1, column 16 - line 1, column 16
      t1 is an unknown type

See https://github.com/purescript/documentation/blob/master/errors/TypesDoNotUnify.md for more information,
or to contribute content related to this error.

And I'm sure it's because of YesNoKindConstraint. If you change the type signature to something like toRed :: forall b. YesNoKindConstraint b => YesNoProxy b -> String it works but I'm not sure it's the right thing to do?

I'm not sure why this is happening, shouldn't instance yesYesNo :: IsYesNoKind YesK take care of the constraint?

@JordanMartinez
Copy link
Owner

JordanMartinez commented Nov 24, 2018

While applying the last fixes I found out that the example with toRed/toBlue doesn't work

Those aren't supposed to work (hence why they are commented out). I wrote that section when I didn't fully understand how that concept (using type-level functions to compute things via unification) was even possible.

Sometime later, I wrote this file, which shows why that idea is actually accurate. This PR reminded me that I hadn't fixed that explanation yet, so I was hoping to fix it after you finished the PR.

Edit: Thus, toRed and toBlue are value-level functions which should be converted into type-level functions via type constraints ToColor input output => whose only instances are:

  • ToColor YesK Red
  • ToColor NoK Blue

@razcore-rad
Copy link
Contributor Author

Alright then, I think I'm done fixing all the stuff we discussed so far so you can hopefully merge this now so we can get to the next thing

@JordanMartinez
Copy link
Owner

Looks good. Thanks for your contribution!

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.

None yet

2 participants