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

strong-path types are restricted to type parameters with kind * #47

Open
craigmc08 opened this issue Jun 8, 2023 · 4 comments
Open

Comments

@craigmc08
Copy link

Currently, the types in this package do not have kind polymorphism, meaning you can only have Dir a if a :: *. But sometimes it would be convenient to allow a to have a different kind.

For example, imagine I want to define a function readREADME :: Project -> IO String which gets the README file from a couple of explicitly defined projects:

data Project = WaspcProject | WasplsProject

To do this with strong-path, I would like to be able to write:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}

data Project = WaspcProject | WasplsProject

readREADME :: Project -> IO String
readREADME project =
  let readmeFile = case
        WaspcProject -> waspcProjectDir </> readmeFileInProjectDir
        WasplsProject -> wasplsProjectDir </> readmeFileInProjectDir
  in readFile $ toFilePath readmeFile

data READMEFile

readmeFileInProjectDir :: forall (base :: Project). Path' (Rel base) (File READMEFile)
readmeFileInProjectDir = [relfile|README.md|]

waspcProjectDir :: Path' Abs (Dir 'WaspcProject)
waspcProjectDir = [absdir|~/waspc|]

wasplsProjectDir :: Path' Abs (Dir 'WasplsProject)
wasplsProjectDir = [absdir|~/waspls|]

Currently, I have define some extra types WaspcDir and WasplsDir, and then I have to make sure to keep those types in-sync with Project in case I add more constructors. I would also have to make a typeclass to act similar to the Project kind that I could use to limit what readmeFileInProjectDir can be joined with. The goal is to reduce that little bit of boilerplate and work required to keep the constructors and types in-sync.

I think this should be possible to do by enabling -XPolyKinds in this package.

@Martinsos
Copy link
Member

Oh interesting!

Package is relatively simple and has instructions for running and testing. If you want to give it a try and see if you can easily get it working, feel free to try to create a PR.
I will probably not do it very soon because I don't know anything about PolyKinds and only little about DataKinds, so it will take me some time to get to this.

@Martinsos
Copy link
Member

Martinsos commented Jun 9, 2023

Just to be clear: you want this in the example below so you don't have to write:

readmeFileInWaspcProjectDir :: Path' (Rel 'WaspcProject) (File READMEFile)
readmeFileInWaspcProjectDir = [relfile|README.md|]

readmeFileInWasplsProjectDir :: Path' (Rel 'WasplsProject) (File READMEFile)
readmeFileInWasplsProjectDir = [relfile|README.md|]

Instead, you want to capture it in a simpler fashion that both of these dirs have the README in same path inside them?

@craigmc08
Copy link
Author

Just to be clear: you want this in the example below so you don't have to write:

readmeFileInWaspcProjectDir :: Path' (Rel 'WaspcProject) (File READMEFile)
readmeFileInWaspcProjectDir = [relfile|README.md|]

readmeFileInWasplsProjectDir :: Path' (Rel 'WasplsProject) (File READMEFile)
readmeFileInWasplsProjectDir = [relfile|README.md|]

Instead, you want to capture it in a simpler fashion that both of these dirs have the README in same path inside them?

I want this feature so I don't have to write:

data Project = WaspcProject | WasplsProject

readREADME :: Project -> IO String
readREADME project =
  let readmeFile = case
        WaspcProject -> waspcProjectDir </> readmeFileInProjectDir
        WasplsProject -> wasplsProjectDir </> readmeFileInProjectDir
  in readFile $ toFilePath readmeFile

data READMEFile

-- Duplication here: If I change definition of 'Project' I have to make sure to do the same thing to these types too
class ProjectDir where
data WaspcProjectDir deriving (ProjectDir)
data WasplsProjectDir deriving (ProjectDir)

readmeFileInProjectDir :: ProjectDir dir => Path' (Rel dir) (File READMEFile)
readmeFileInProjectDir = [relfile|README.md|]

waspcProjectDir :: Path' Abs (Dir WaspcProjectDir)
waspcProjectDir = [absdir|~/waspc|]

wasplsProjectDir :: Path' Abs (Dir WasplsProjectDir)
wasplsProjectDir = [absdir|~/waspls|]

@Martinsos
Copy link
Member

Right, sure! That is one solution, with a class. Other solution is what I provided above, with repeating the path.

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

No branches or pull requests

2 participants