Skip to content

Revise class constructor/accessor representation#928

Closed
garyb wants to merge 5 commits intomasterfrom
corefn-class-repr
Closed

Revise class constructor/accessor representation#928
garyb wants to merge 5 commits intomasterfrom
corefn-class-repr

Conversation

@garyb
Copy link
Copy Markdown
Member

@garyb garyb commented Mar 1, 2015

This is almost working, but not quite. All that nonsense about special cases for class constructors, class constructor applications, member accessors is gone in favour of representing classes as standard data constructors... however, now I get a type error when trying to compile the prelude:

Error in module Prelude:
Error at  line 420, column 3 - line 422, column 3:
  Error in value declaration bindArr:
  Error checking that value
    Prelude.Bind(\__unused -> <<superclass dict Prelude.Apply>>)(\m -> \f -> \x -> f(m(x))(x))
  has type
    forall r. Prelude.Bind (Prim.Function r)
  Error checking that value
    Prelude.Bind(\__unused -> <<superclass dict Prelude.Apply>>)(\m -> \f -> \x -> f(m(x))(x))
  has type
    Prelude.Bind (Prim.Function r648)
  Error applying function
    Prelude.Bind(\__unused -> <<dict False>>)
  of type
    (forall a b. u649 a -> (a -> u649 b) -> u649 b) -> Prelude.Bind u649
  to argument
    \m -> \f -> \x -> f(m(x))(x)
  Error checking that value
    \m -> \f -> \x -> f(m(x))(x)
  has type
    forall a b. u649 a -> (a -> u649 b) -> u649 b
  Error checking that value
    \m -> \f -> \x -> f(m(x))(x)
  has type
    forall a. u649 a -> (a -> u649 b653) -> u649 b653
  Error checking that value
    \m -> \f -> \x -> f(m(x))(x)
  has type
    u649 a655 -> (a655 -> u649 b653) -> u649 b653
  Error at  line 303, column 5 - line 305, column 3:
    Error checking that value
      \f -> \x -> f(m(x))(x)
    has type
      (a655 -> u649 b653) -> u649 b653
    Error checking that value
      \x -> f(m(x))(x)
    has type
      u649 b653
    Expression
      \x -> f(m(x))(x)
    does not have type
      u649 b653
See https://github.com/purescript/purescript/wiki/Error-Code-ExprDoesNotHaveType for more information, or to contribute content related to this error.

I could use a hand trying to figure out what's going wrong here, I've experimented a bit compiling something with no-prelude thinking it might be to do with higher kinded classes, but a Functor class and instance certainly works ok.

Will close #781 when finished.

garyb added 2 commits March 1, 2015 16:07
Having them in the environment alone is not enough, as typeclass
desugaring doesn't extend the environment, it only alters the AST.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

There's also this, which is annoying.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does this process need to loop until a fixed point? I'm guessing not.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

No it doesn't, it's just that desugaring typeclasses reintroduces more cases. I tried juggling the order but my attempts resulted in other problems.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you desugar the new cases when you generate them?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah, perhaps - I barely remember what I was doing now. It's not too complicated though, I'm just not sure where the additional cases came from off the top of my head.

@garyb
Copy link
Copy Markdown
Member Author

garyb commented Mar 1, 2015

This only occurs for the applyArr and bindArr instances it seems. The applyArr error is almost identical.

@paf31
Copy link
Copy Markdown
Contributor

paf31 commented Mar 1, 2015

This seems related to #862

What does the Bind instance desugar into now?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can just be lazy here: [0..] and then even move this out into a CAF at the top level to be reused.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Will do.

@garyb
Copy link
Copy Markdown
Member Author

garyb commented Mar 1, 2015

bindArr :: forall r. Bind (Function r)
bindArr = Bind (\__unused -> applyArr) (\m -> \f -> \x -> f(m(x))(x))

@paf31
Copy link
Copy Markdown
Contributor

paf31 commented Mar 1, 2015

I think it would help if it could be

bindArr = Bind (\__unused -> applyArr) ((\m -> \f -> \x -> f(m(x))(x)) :: forall r a b. (r -> a) -> (a -> r -> b) -> r -> b)

@garyb
Copy link
Copy Markdown
Member Author

garyb commented Mar 1, 2015

I can produce a type like forall a b. (r -> a) -> (a -> r -> b) -> r -> b easily enough for that (which also doesn't work alas), is it right that the r is also quantified in your example?

@paf31
Copy link
Copy Markdown
Contributor

paf31 commented Mar 1, 2015

No, sorry, it should be the skolemized type.

@garyb
Copy link
Copy Markdown
Member Author

garyb commented Mar 1, 2015

Get the same exact error with that:

Error in module Prelude:
Error at  line 420, column 3 - line 422, column 3:
  Error in value declaration bindArr:
  Error checking that value
    Prelude.Bind(\__unused -> <<superclass dict Prelude.Apply>>)((\m -> \f -> \x -> f(m(x))(x) :: forall a b. (r -> a) -> (a -> r -> b) -> r -> b))
  has type
    forall r. Prelude.Bind (Prim.Function r)
  Error checking that value
    Prelude.Bind(\__unused -> <<superclass dict Prelude.Apply>>)((\m -> \f -> \x -> f(m(x))(x) :: forall a b. (r659 -> a) -> (a -> r659 -> b) -> r659 -> b))
  has type
    Prelude.Bind (Prim.Function r659)
  Error applying function
    ((Prelude.Bind :: ({  } -> Prelude.Apply u660) -> (forall a b. u660 a -> (a -> u660 b) -> u660 b) -> Prelude.Bind u660)((\__unused -> <<dict False>> :: {  } -> Prelude.Apply u660)) :: (forall a b. u660 a -> (a -> u660 b) -> u660 b) -> Prelude.Bind u660)
  of type
    (forall a b. u660 a -> (a -> u660 b) -> u660 b) -> Prelude.Bind u660
  to argument
    (\m -> \f -> \x -> f(m(x))(x) :: forall a b. (r659 -> a) -> (a -> r659 -> b) -> r659 -> b)
  Error checking that value
    (\m -> \f -> \x -> f(m(x))(x) :: forall a b. (r659 -> a) -> (a -> r659 -> b) -> r659 -> b)
  has type
    forall a b. u660 a -> (a -> u660 b) -> u660 b
  Error checking that value
    (\m -> \f -> \x -> f(m(x))(x) :: forall a b. (r659 -> a) -> (a -> r659 -> b) -> r659 -> b)
  has type
    forall a. u660 a -> (a -> u660 b664) -> u660 b664
  Error checking that value
    (\m -> \f -> \x -> f(m(x))(x) :: forall a b. (r659 -> a) -> (a -> r659 -> b) -> r659 -> b)
  has type
    u660 a666 -> (a666 -> u660 b664) -> u660 b664
  Error at  line 303, column 5 - line 305, column 3:
    Error checking that value
      \m -> \f -> \x -> f(m(x))(x)
    has type
      u660 a666 -> (a666 -> u660 b664) -> u660 b664
    Error checking that value
      \f -> \x -> f(m(x))(x)
    has type
      (a666 -> u660 b664) -> u660 b664
    Error checking that value
      \x -> f(m(x))(x)
    has type
      u660 b664
    Expression
      \x -> f(m(x))(x)
    does not have type
      u660 b664

@paf31
Copy link
Copy Markdown
Contributor

paf31 commented Mar 1, 2015

Ok, I think we can save this by changing a case in check: when we check a TypedValue against a type. I'll explain on IRC.

@garyb
Copy link
Copy Markdown
Member Author

garyb commented Mar 1, 2015

Just pushed those tweaks, is that what you had in mind?

@coveralls
Copy link
Copy Markdown

Coverage Status

Coverage decreased (-8.67%) to 75.25% when pulling dea69b6 on corefn-class-repr into 388a369 on master.

@garyb
Copy link
Copy Markdown
Member Author

garyb commented Mar 1, 2015

That's a shame, I was hoping it was something I was doing wrong! Here's the problem with Trans after changing check':

Warning: Error in module Control.Monad.Cont.Trans:
Error at src/Control/Monad/Cont/Trans.purs line 3, column 1 - line 5, column 1:
  Error in value declaration monadTransContT:
  Error checking that value
    Control.Monad.Trans.MonadTrans((\m -> Control.Monad.Cont.Trans.ContT(\k -> Prelude.(>>=)(m)(k)) :: forall m a. (Prelude.Monad m) => m a -> Control.Monad.Cont.Trans.ContT r m a))
  has type
    forall r. Control.Monad.Trans.MonadTrans (Control.Monad.Cont.Trans.ContT r)
  Error checking that value
    Control.Monad.Trans.MonadTrans((\m -> Control.Monad.Cont.Trans.ContT(\k -> Prelude.(>>=)(m)(k)) :: forall m a. (Prelude.Monad m) => m a -> Control.Monad.Cont.Trans.ContT r1602 m a))
  has type
    Control.Monad.Trans.MonadTrans (Control.Monad.Cont.Trans.ContT r1602)
  Error applying function
    (Control.Monad.Trans.MonadTrans :: (forall m a. (Prelude.Monad m) => m a -> u1603 m a) -> Control.Monad.Trans.MonadTrans u1603)
  of type
    (forall m a. (Prelude.Monad m) => m a -> u1603 m a) -> Control.Monad.Trans.MonadTrans u1603
  to argument
    (\m -> Control.Monad.Cont.Trans.ContT(\k -> Prelude.(>>=)(m)(k)) :: forall m a. (Prelude.Monad m) => m a -> Control.Monad.Cont.Trans.ContT r1602 m a)
  Error checking that value
    (\m -> Control.Monad.Cont.Trans.ContT(\k -> Prelude.(>>=)(m)(k)) :: forall m a. (Prelude.Monad m) => m a -> Control.Monad.Cont.Trans.ContT r1602 m a)
  has type
    forall m a. (Prelude.Monad m) => m a -> u1603 m a
  Error checking that value
    (\m -> Control.Monad.Cont.Trans.ContT(\k -> Prelude.(>>=)(m)(k)) :: forall m a. (Prelude.Monad m) => m a -> Control.Monad.Cont.Trans.ContT r1602 m a)
  has type
    forall m. (Prelude.Monad m) => m a1607 -> u1603 m a1607
  Error checking that value
    (\m -> Control.Monad.Cont.Trans.ContT(\k -> Prelude.(>>=)(m)(k)) :: forall m a. (Prelude.Monad m) => m a -> Control.Monad.Cont.Trans.ContT r1602 m a)
  has type
    (Prelude.Monad m1609) => m1609 a1607 -> u1603 m1609 a1607
  Error checking that value
    (\m -> Control.Monad.Cont.Trans.ContT(\k -> Prelude.(>>=)(m)(k)) :: forall m a. (Prelude.Monad m) => m a -> Control.Monad.Cont.Trans.ContT r1602 m a)
  has type
    m1609 a1607 -> u1603 m1609 a1607
  Error at src/Control/Monad/Cont/Trans.purs line 34, column 3 - line 34, column 32:
    Error checking that value
      (\m -> Control.Monad.Cont.Trans.ContT(\k -> Prelude.(>>=)(m)(k)))(<<dict True>>)
    has type
      forall m a. (Prelude.Monad m) => m a -> Control.Monad.Cont.Trans.ContT r1602 m a
    Error checking that value
      (\m -> Control.Monad.Cont.Trans.ContT(\k -> Prelude.(>>=)(m)(k)))(<<dict True>>)
    has type
      forall m. (Prelude.Monad m) => m a1615 -> Control.Monad.Cont.Trans.ContT r1602 m a1615
    Error checking that value
      (\m -> Control.Monad.Cont.Trans.ContT(\k -> Prelude.(>>=)(m)(k)))(<<dict True>>)
    has type
      (Prelude.Monad m1617) => m1617 a1615 -> Control.Monad.Cont.Trans.ContT r1602 m1617 a1615
    Error checking that value
      (\m -> Control.Monad.Cont.Trans.ContT(\k -> Prelude.(>>=)(m)(k)))(<<dict True>>)
    has type
      m1617 a1615 -> Control.Monad.Cont.Trans.ContT r1602 m1617 a1615
    Error applying function
      (\m -> ((Control.Monad.Cont.Trans.ContT :: ((u1619 -> u1620 u1621) -> u1620 u1621) -> Control.Monad.Cont.Trans.ContT u1621 u1620 u1619)((\k -> (((Prelude.(>>=) :: forall a b m. (Prelude.Bind m) => m a -> (a -> m b) -> m b)(<<dict True>>)((m :: u1622 u1624)) :: (u1624 -> u1622 u1623) -> u1622 u1623)((k :: u1624 -> u1622 u1623)) :: u1620 u1621) :: (u1619 -> u1620 u1621) -> u1620 u1621)) :: Control.Monad.Cont.Trans.ContT u1621 u1620 u1619) :: u1618 -> Control.Monad.Cont.Trans.ContT u1621 u1620 u1619)
    of type
      u1618 -> Control.Monad.Cont.Trans.ContT u1621 u1620 u1619
    to argument
      <<dict True>>
    Error checking that value
      <<dict True>>
    has type
      u1622 u1619
    Expression
      <<dict True>>
    does not have type
      u1622 u1619

@garyb
Copy link
Copy Markdown
Member Author

garyb commented Mar 1, 2015

<<dict True>> is actually for Prelude.Monad u1613, the pretty printer isn't quite right for class dictionaries... but then I'm not sure why that value is there at all, maybe it is something I'm missing still.

@garyb
Copy link
Copy Markdown
Member Author

garyb commented Mar 1, 2015

Ok this isn't check' related, I think I know what's wrong.

@garyb
Copy link
Copy Markdown
Member Author

garyb commented Mar 1, 2015

Or not... I can make some progress by using TypedVal False ... for the members, but then there's this:

Error in module Optic.Contains:
Error in value declaration containsSet:
Error checking that type
  k15 -> Optic.Index.Types.LensP<(Data.Set.Set k15),Prim.Boolean>
subsumes type
  u16 -> (forall f. (Prelude.Functor f) => (Prim.Boolean -> f Prim.Boolean) -> u17 -> f u17)
Error checking that type
  Optic.Index.Types.LensP<(Data.Set.Set k15),Prim.Boolean>
subsumes type
  forall f. (Prelude.Functor f) => (Prim.Boolean -> f Prim.Boolean) -> u17 -> f u17
Error checking that type
  Optic.Index.Types.LensP<(Data.Set.Set k15),Prim.Boolean>
subsumes type
  (Prelude.Functor f19) => (Prim.Boolean -> f19 Prim.Boolean) -> u17 -> f19 u17
Error checking that type
  forall f. (Prelude.Functor f) => (Prim.Boolean -> f Prim.Boolean) -> Data.Set.Set k15 -> f (Data.Set.Set k15)
subsumes type
  (Prelude.Functor f19) => (Prim.Boolean -> f19 Prim.Boolean) -> u17 -> f19 u17
Error checking that type
  (Prelude.Functor u21) => (Prim.Boolean -> u21 Prim.Boolean) -> Data.Set.Set k15 -> u21 (Data.Set.Set k15)
subsumes type
  (Prelude.Functor f19) => (Prim.Boolean -> f19 Prim.Boolean) -> u17 -> f19 u17
Error at bower_components/purescript-index/src/Optic/Contains.purs line 12, column 5 - line 13, column 69:
  Cannot unify constrained type
    (Prelude.Functor u21) => (Prim.Boolean -> u21 Prim.Boolean) -> Data.Set.Set k15 -> u21 (Data.Set.Set k15)
  with type
    (Prelude.Functor f19) => (Prim.Boolean -> f19 Prim.Boolean) -> u17 -> f19 u17

I'm giving up for tonight.

@coveralls
Copy link
Copy Markdown

Coverage Status

Coverage decreased (-4.4%) to 79.52% when pulling 4606aac on corefn-class-repr into 388a369 on master.

@puffnfresh
Copy link
Copy Markdown
Contributor

Compiling Prelude and purescript-index seem to now work fine. What's left to do? Fix the tests?

@garyb
Copy link
Copy Markdown
Member Author

garyb commented Mar 8, 2015

"Fixing" it so purescript-index failed wasn't really the right approach, so yeah, tests and now Trans are failing again. It's because class dictionaries are being inserted in places they shouldn't be. I'm going to try and make some progress again today.

@garyb
Copy link
Copy Markdown
Member Author

garyb commented Mar 8, 2015

I think I've discovered another bug in the typechecker actually, different from the first one:

data Sequence t = Sequence (forall m a. (Monad m) => t (m a) -> m (t a))

sequence :: forall t. Sequence t -> (forall m a. (Monad m) => t (m a) -> m (t a))
sequence (Sequence s) = s

sequenceArraySeq :: forall m a. (Monad m) => Array (m a) -> m (Array a)
sequenceArraySeq [] = pure []
sequenceArraySeq (x:xs) = (:) <$> x <*> sequenceArraySeq xs

-- This is fine
sequenceArray :: Sequence []
sequenceArray = Sequence (sequenceArraySeq)

-- So is this:
sequenceArray' :: Sequence []
sequenceArray' = Sequence ((\val -> case val of
  [] -> pure []
  (x:xs) -> (:) <$> x <*> sequence sequenceArray' xs))

-- This is not: 
sequenceArray'' :: Sequence []
sequenceArray'' = Sequence (sequenceArraySeq :: forall m a. (Monad m) => Array (m a) -> m (Array a))

-- Nor is this:
sequenceArray''' :: Sequence []
sequenceArray''' = Sequence ((\val -> case val of
  [] -> pure []
  (x:xs) -> (:) <$> x <*> sequence sequenceArray''' xs) :: forall m a. (Monad m) => Array (m a) -> m (Array a))

So it seems to be when using explicit types with constraints when passing a value into a function (I tried a normal function as well as a constructor, and actually found another bug there I'll open an issue for, both failed with the same kind of error).

The error raised in both cases is like this, and is the same error as occurs in Trans, a dictionary being inserted where it should not be:

Error in module Main:
Error in value declaration sequenceArray'':
Error at examples\passing\SequenceDesugared.purs line 32, column 31 - line 32, column 102:
  Expression
    <<dict True>>
  does not have type
    [u1563 u1562]

@garyb
Copy link
Copy Markdown
Member Author

garyb commented Mar 8, 2015

So the situation now is:

  • If I don't add explicit types to the instance members, bindArr and applyArr fail with the error mentioned in the first comment.
  • If I do add explicit types to the instance members, things like the above fail due to an unnecessary dictionary insertion.

Conflicts:
	src/Language/PureScript/Pretty/Values.hs
	src/Language/PureScript/TypeChecker/Types.hs
@garyb
Copy link
Copy Markdown
Member Author

garyb commented Mar 8, 2015

@paf31 instead of the half explanations I was giving in IRC earlier, here's where this is at.

Apart from type checker issues this is basically done. Data constructors are now generated for classes, instances/dictionaries are values that use the constructors, and member accessors destructure the data type to extract the instance members.

A class and instance like this:

class Sequence t where
  sequence :: forall m a. (Monad m) => t (m a) -> m (t a)

instance sequenceArray :: Sequence [] where
  sequence [] = pure []
  sequence (x:xs) = (:) <$> x <*> sequence xs

Will be desugared as this:

data Sequence t = Sequence (forall m a. (Monad m) => t (m a) -> m (t a))

sequence :: forall t. Sequence t -> (forall m a. (Monad m) => t (m a) -> m (t a))
sequence (Sequence s) = s

sequenceArray :: Sequence []
sequenceArray = Sequence ((\val -> case val of
  [] -> pure []
  (x:xs) -> (:) <$> x <*> sequence sequenceArray xs) :: forall m a. (Monad m) => [m a] -> m [a])

The problem now is how to deal with the instances during type checking. The code currently has two problems - purescript-index doesn't typecheck, and the generated code is incorrect as there are some cases where an unnecessary dictionary appears. For example, in the case of sequenceArray, we end up with something like this:

sequenceArray :: Sequence []
sequenceArray = Sequence ((\__dict_Monad_18 -> \__dict_Monad_19 \val -> case val of
  [] -> pure []
  (x:xs) -> (:) <$> x <*> sequence __dict_Monad_19 xs) :: forall m a. (Monad m) => [m a] -> m [a])

(We only want the __dict_Monad_19 argument here.) This is happening because we're using ty1' in the check here as per your suggestion. ty1' is forall m a. (Prelude.Monad m) => [m a] -> m [a], and having the constraint in there is where the unwanted argument comes from.

If we try and use ty2' in that check then the prelude won't even compile because of the bindArr and applyArr instances, which I think you said was happening because the substitution wasn't being fully applied - ty2' currently comes out as u1552 (m1558 a1556) -> m1558 (u1552 a1556).

The fix I applied in master to resolve the constrained type argument only works when we're using ty2' in check, so now I think I'm stuck again.

I think that covers it!

@garyb garyb mentioned this pull request Mar 25, 2015
7 tasks
@garyb garyb added this to the 0.8.0 milestone Apr 26, 2015
@garyb garyb mentioned this pull request Sep 13, 2015
@paf31 paf31 removed this from the 0.8.0 milestone Nov 8, 2015
@texastoland
Copy link
Copy Markdown

Stumbled on this and curious if it was abandoned?

@garyb
Copy link
Copy Markdown
Member Author

garyb commented Apr 8, 2016

It's not, I just haven't returned to it yet, other things have seemed more pressing!

@garyb garyb mentioned this pull request Jun 22, 2016
@garyb garyb closed this Jun 25, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Represent typeclasses as data constructors in functional core

5 participants