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

Use rosetree to store capability type. #212

Merged
merged 3 commits into from
Sep 24, 2015
Merged

Use rosetree to store capability type. #212

merged 3 commits into from
Sep 24, 2015

Conversation

albertnetymk
Copy link
Contributor

No description provided.

@TobiasWrigstad
Copy link
Contributor

What is this?

@albertnetymk
Copy link
Contributor Author

Traits implemented by one class are combined using + and * operators. Before, only + is supported, and they are stored in a list. Now in order to support two operators, the structure needs to be saved. This PR use rose tree to save all the traits implemented.

@TobiasWrigstad
Copy link
Contributor

OK. So, is it fair to say that this PR should be renamed "Adding conjunction composition for traits"?

@TobiasWrigstad
Copy link
Contributor

Bump @EliasC

@albertnetymk
Copy link
Contributor Author

OK. So, is it fair to say that this PR should be renamed "Adding conjunction composition for traits"?

I would be reluctant to call it so, for "adding conjunction composition" implies that typechecker catches malformed usages and emit correct C code. On the contrary, this PR only adds the rose tree data structure to store all the traits.

map TraitType ((toList . typeTree) capability)
typesFromCapability ty =
error $ "Types.hs: Can't get the traits of non-capability type "
++ showWithKind ty
Copy link
Contributor

Choose a reason for hiding this comment

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

I like the name traitsFromCapability better since it specifies the granularity of the resulting types. It is not clear to me (without reading the code) what typesFromCapability gives me for A * (B + C), while with traitsFromCapability it's obvious that it is [A, B, C] (in some order).

@albertnetymk
Copy link
Contributor Author

Have looked at all the cases where typesFromCapability is used, the prefix types feels OK, for the return type is [Type] anyway.

let
par_types = map toList $ map (fmap TraitType) ts
in
concatMap collect ts ++ [par_types]
Copy link
Contributor

Choose a reason for hiding this comment

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

conjunctiveTraitsFromCapability is a better name I think, if this function takes a conjunctive type A*B and returns [[A], [B]] (I don't see how the third level of list-nesting is used, but maybe you get the point). parallelTypes is confusing since we have a Par type.

@EliasC
Copy link
Contributor

EliasC commented Sep 23, 2015

Have looked at all the cases where typesFromCapability is used, the prefix types feels OK, for the return type is [Type] anyway.

The return type just strengthens my point I think. Reading the name and the type I have no way of knowing that all the types in the resulting list are actually trait types!

@albertnetymk
Copy link
Contributor Author

Yes, conjunctive is surely better.

@EliasC
Copy link
Contributor

EliasC commented Sep 23, 2015

Yes, conjunctive is surely better.

Could you give a quick explanation of what it returns as well? I didn't get why it's a list of lists of lists.


instance Traversable RoseTree where
traverse f (Leaf i) = Leaf <$> f i
traverse f (RoseTree op ts) = RoseTree op <$> traverse (traverse f) ts
Copy link
Contributor

Choose a reason for hiding this comment

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

It's nice how the structure is made instances of these type classes so that normal map, mapM, etc. works!

@albertnetymk
Copy link
Contributor Author

Reading the name and the type I have no way of knowing that all the types in the resulting list are actually trait types!

That's true, but the function name could be changed to arbitrary strings, while the signature is checked all the time. It's good to rely on the signature instead of the name. BTW, we don't have trait type, only TraitType value constructor.

I didn't get why it's a list of lists of lists.

I think it's because there are multiple levels of conjunctive traits, since it's a tree.

@EliasC
Copy link
Contributor

EliasC commented Sep 23, 2015

That's true, but the function name could be changed to arbitrary strings, while the signature is checked all the time.

That's hardly an argument to choose bad names though :)

I will drop this for now and bring it up again if it causes problems while programming.


is_val :: FieldDecl -> TypecheckM ()
is_val f = unless (isValField f) $ tcError $
printf "'%s' is not val field" $ show f
Copy link
Contributor

Choose a reason for hiding this comment

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

This error message should be improved (something like Disjunctive traits A and B cannot have overlapping mutable field requirements), but I'm ready to push that to a later commit.

@EliasC
Copy link
Contributor

EliasC commented Sep 23, 2015

I think it's because there are multiple levels of conjunctive traits, since it's a tree.

So something like this?

The innermost lists are collection of disjunctive traits that may share fields. The sibling lists of those lists contain traits that are all conjunctive between lists. Each list of these lists contain the traits of different levels of the tree.

It feels like you should be able to do this with only two levels so that only the first two "steps" above are needed. Please let me know if you can shed any light on this!

@EliasC
Copy link
Contributor

EliasC commented Sep 23, 2015

When the discussed issues are fixed, I think this is ready to be merged!

@EliasC
Copy link
Contributor

EliasC commented Sep 23, 2015

(+rebasing)

@albertnetymk
Copy link
Contributor Author

It feels like you should be able to do this with only two levels so that only the first two "steps" above are needed.

It's possible that I overcomplicated the situation; for A*B + C*D, it returns something like this I believe:

[[[A],[B]],[[C],[D]]]

@EliasC
Copy link
Contributor

EliasC commented Sep 24, 2015

Thanks for the explanation! Let's leave it as it is and refactor it if we find a need for it.

There is still a spelling mistake in Util.hs. resovle_capa should be resolve_capa (or rather resolveCapability, since that is the naming convention for the rest of the surrounding function!). After this I think the PR is ready to be merged.

One comment on the error message of overlapping fields though. Right now the message is

'f : T' needs to be defined as val field in both conjunctive traits 'Foo' and 'Bar'

which describes a solution to get rid of the error, but not the reason there was an error in the first place. I suggest instead

Conjunctive traits 'Foo' and 'Bar' cannot share mutable field 'f : T'

which describes what design choice lead to the error, which is more useful in teaching the programmer how to avoid errors like this in the future. If you want to also describe a solution you could add Consider turning it into a val-field afterwards.

@albertnetymk
Copy link
Contributor Author

I have found the idea of using camel and snake to distinguish the public and private functions very helpful. Encourage others to try it out.

@kikofernandez
Copy link
Contributor

I would rather suggest that we come up with some general guidelines for writing code, instead of everyone choosing what to do. Now, @albertnetymk suggests to use snake case for private functions. I suggest that everyone uses snakel case: this_Is_Snakel_Case... hope everyone gets it :)

@EliasC
Copy link
Contributor

EliasC commented Sep 24, 2015

@albertnetymk For the nth time point you to our own guidelines for contibuting:

Respect conventions

You might love tabs in your source code. You might
really, really love them. But if re submitting a pull request to a project that
uses spaces, you're going have to suck it up and use them.

Aside from coding style, projects might have more subtle conventions that it
makes sense to follow. Perhaps private functions never have docstrings, or
perhaps commit messages are always written in the imperative, present tense. Try
to ensure your contributions to the project don't stand out as
unusual.

Although I prefer camelCase (as you know), that's not why I'm arguing that you should use it. My point is that you need to respect the conventions of the code you're contributing to. Here is the where clause in question:

          resovle_capa :: Type -> TypecheckM Type
          resovle_capa t
            | emptyCapability t = return t
            | singleCapability t = resolveType $ head $ typesFromCapability t
            | otherwise =
              mapM_ resolveSingleTrait (typesFromCapability ty) >> return ty

          resolveSingleTrait t = do
            result <- asks $ traitLookup t
            when (isNothing result) $
                   tcError $ "Couldn't find trait '" ++ getId t ++ "'"

All the functions visible here are have descriptive names in camelCase without abbreviations. When you add something to this context and ignore these conventions, you deteriorate the quality of the code. It would make more sense to rename resolveSingleTrait into resovle_sngl_trt so that there at least is a convention locally (but it should be obvious that this would not improve the code).

I agree with @kikofernandez. We need to agree on a convention that we can all follow. It is obvious that these discussions have no effect.

@EliasC
Copy link
Contributor

EliasC commented Sep 24, 2015

I will merge this now, but we should continue the discussion about coding conventions. I started an issue for it: #224

EliasC added a commit that referenced this pull request Sep 24, 2015
Use rosetree to store capability type.
@EliasC EliasC merged commit aa0aeb9 into parapluu:master Sep 24, 2015
@kaeluka
Copy link
Contributor

kaeluka commented Sep 24, 2015

I agree with @kikofernandez. We need to agree on a convention that we can all follow. It is obvious that these discussions have no effect.

In this specific case, we have the convention -- you linked to it. @albertnetymk just doesn't adhere to it, so this is a problem of programmer discipline/weak enforcing, not lack of convention.

@albertnetymk albertnetymk deleted the rosetree branch September 24, 2015 10:41
fmap f (Leaf i) = Leaf $ f i
fmap f (RoseTree op ts) = RoseTree op $ map (fmap f) ts

instance Foldable RoseTree where
Copy link
Contributor

Choose a reason for hiding this comment

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

This is breaking the build, Foldable is in Prelude only since ghc 7.10

https://wiki.haskell.org/Foldable_Traversable_In_Prelude

@EliasC EliasC mentioned this pull request Oct 6, 2015
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.

5 participants