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

InvalidInstanceHead error can be subverted via vacuous fundep #4474

Open
Quelklef opened this issue May 15, 2023 · 2 comments
Open

InvalidInstanceHead error can be subverted via vacuous fundep #4474

Quelklef opened this issue May 15, 2023 · 2 comments
Assignees

Comments

@Quelklef
Copy link

Quelklef commented May 15, 2023

Description

An instance head containing the empty row () normally causes an InvalidInstanceHead. As the compiler instructs, by adding appropriate fundeps to the class one can make the instance valid. Surprisingly, one can also make the instance valid by adding a fundep of the form a -> a where a is the type variable being instantiated to the empty row ().

To Reproduce

Run the following program in Purescript 0.15.8 (online playground):

module Main where

-- Fails, as expected
class A a b
-- instance A Int ()

-- Works, as expected
class B a b | a -> b
instance B Int () 

-- Works, surprisingly
class C a b | b -> b
instance C Int ()

Expected behavior

The instance with the vacuous fundep a -> a should (?) also cause an InvalidInstanceHead error

Additional context

The docs for InvalidInstanceHead say "when you see this error, it's because you're trying to write an instance of a given class that pattern matches on some row type [...] there isn't really a sensible way to match on row."

I don't know if this is worth anything, but it's kinda unclear to me what's unsensible about matching on row types, and I can't find an explanation online. In fact, by abusing this "vacuous fundeps circumvents InvalidInstanceHead" bug I was able to write a split function which can split a record into subrecords decided at compile time. eg,

splitMe :: { a :: Int, b :: String } -> { a :: Int } /\ { b :: String }
splitMe = split

This function is quite handy in a project I'm working on. Of course it could be implemented with RowToList, but I think that would require unsafeCoerce whereas the current implementation does not.

PureScript version

0.15.8

@Quelklef
Copy link
Author

FWIW version 0.15.4 does not seem to exhibit this behaviour -- the example code fails with InvalidInsteadHead as expected

@rhendric
Copy link
Member

AFAIK the only thing likely to have caused this in that timeframe would be #4195.

@MonoidMusician MonoidMusician self-assigned this May 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants