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

Proof of concept for higher-order DSL API #36

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

gergoerdi
Copy link

This pull request is not ready for merging, but I want to use the Github PR interface to discuss it.

I just saw your Berlin FP Meetup talk, and I noticed that in the DSL you require variables to be explicitly created by the user. I think a much nicer API is if you allow |- to allow functions on the right-hand side. In this PR, I illustrate how you can do that, and also use code comments to show the things that are still TODO in my code.

The money shot is this:

            reachable' |- \ a b -> edge(a, b)
            reachable' |- \ a b -> reachable(a, b)

The fact that you need a slightly different reachable' and reachable on the two sides is something that I think you will be able to fix.

@@ -92,6 +93,7 @@ module Language.Souffle.Experimental
, __
, underscore
, (|-)
, (||-)
Copy link
Author

Choose a reason for hiding this comment

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

Naming is hard, let's go shopping!

I think if this is finished, you can just use |- for the new one, and get rid of the old one everywhere.

Comment on lines 1008 to 1019
class GenVars (ts :: [Type]) where
genVars :: Proxy ts -> Tuple 'Relation ts

varI :: Int -> Term 'Relation a
varI i = VarTerm $ "x" <> T.pack (show i)

instance GenVars '[t] where
genVars _ = varI 0

instance GenVars '[t1, t2] where
genVars _ = (varI 0, varI 1)

Copy link
Author

Choose a reason for hiding this comment

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

This sucks big-time. It should be an inductive definition, instead of requiring separate instances for each tuple length. Also, it should run in one of your variable number-tracking monads, but I decided that life's too short to worry about that for this illustration.

Copy link
Owner

Choose a reason for hiding this comment

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

Yes, tuples are really annoying to work with in Haskell :( main reason I used them is to keep the syntax the same as in Datalog. For now I limited it to 10 instances which is kinda "meh", but it gets the job done.

If you know a better way of handling raw tuples in combination with typeclasses, let me know!

Copy link
Author

Choose a reason for hiding this comment

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

Well the straightforward way would be to use an HList-like product type indexed by its coordinates, through and through, but then you have to use x :> y :> Nil instead of (x, y).

You could carry a list of types everywhere, and convert to a Haskell tuple at the last minute, but that becomes unwieldy on the way back I think -- because of one-tuples, you can't easily have a bijection between Product ts and (t1, ..., tn) :( And if you only want to do the conversion where you do know the ts ,that means you would need a special apply operator instead of . If you are willing to do that, I think you can get both

foo |- \x y -> ...

and

... foo |$| (x, y) ...

@luc-tielen
Copy link
Owner

Hi @gergoerdi, there's a reason I put explicit naming of variables in: code generation.
I didn't mention it in my Berlin talk, unlike in some of the other talks I gave. But this allows for generating datalog code that is still readable (as opposed to using "var1", "var2", ...)
The main reason why I think it might look strange is when writing generic predicates: there it becomes really hard to name variables properly (just like in Haskell we have id :: a -> a).

Technically it's possible to remove the name of the variable from the var function, and just use "var" always as the var name, but this results in less readable code. (You could even define your own var' = var "var" function if you wanted to do this.)

Also, I think you noticed, but I hid the Var constructor so that users are forced to use var, then I can use some logic inside my DSL monad to make sure variables always have a unique name.

@gergoerdi
Copy link
Author

Also, I think you noticed, but I hid the Var constructor so that users are forced to use var, then I can use some logic inside my DSL monad to make sure variables always have a unique name.

Yeah, I think in the second commit I have started using var instead of making VarEs directly.

Bear in mind, I have spent less time looking at the code than I did listening to your (btw, great!) FP Berlin talk.

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.

2 participants