dhall-lang / dhall-json

This repository has moved to https://github.com/dhall-lang/dhall-haskell/tree/master/dhall-json
BSD 3-Clause "New" or "Revised" License
65 stars 6 forks source link

A value that can be either a primitive or a record #2

Closed scott-fleischman closed 7 years ago

scott-fleischman commented 7 years ago

Is it possible to create a Dhall file that will generate the following stack.yaml?

Each item in packages could either be a primitive value (string) or a record.

packages:
- '.'
- location:
    git: git@github.com:Gabriel439/Haskell-Dhall-Library.git
    commit: aeb7d165251a0612538e0ca8f84d60b5aaac6c8d
  subdirs: []
  extra-dep: true

Or written this way, the problem shifts to location, which is either a primitive value or a record.

packages:
- location: '.'
- location:
    git: git@github.com:Gabriel439/Haskell-Dhall-Library.git
    commit: aeb7d165251a0612538e0ca8f84d60b5aaac6c8d
  subdirs: []
  extra-dep: true

My tendency is to reach for Dhall's union type, but that is not a currently supported translation:

Explanation: Only primitive values, records, ❰List❱s, and ❰Optional❱ values can be translated from Dhall to JSON

It might be helpful to allow for unions to translate to overlapping types for situations like this.

Using unions in this way is more similar to TypeScript's union type, since the explicit tag would get lost in translation.

Gabriella439 commented 7 years ago

Yeah, I like this idea! I have a pull request up at #3 which uses your suggestion of unions with the tag stripped. Check it out and let me know if that's what you had in mind

scott-fleischman commented 7 years ago

Yes that works great. Here's a Dhall script to generate the first stack.yaml above.

{ packages =
  [ < path = "."
    | details :
      { location :
        { git : Text
        , commit : Text
        }
      , subdirs : List Text
      , extra-dep : Bool
      }
    >
  , < details =
      { location =
        { git = "git@github.com:Gabriel439/Haskell-Dhall-Library.git"
        , commit = "aeb7d165251a0612538e0ca8f84d60b5aaac6c8d"
        }
      , subdirs = [] : List Text
      , extra-dep = True
      }
    | path : Text
    >
  ]
}

It's a bit verbose to have to specify the alternate union case when it could be inferred, but this certainly allows me to move forward in generating stack.yaml files. Thanks!

Gabriella439 commented 7 years ago

Yeah, what I usually do to cut down on the verbosity is to define or import helper functions for each constructor, like this:

    let makePath    = λ(path : Text) → < path = path | details : ... >
in  let makeDetails = λ(details : ...) → < details = details | path : ... >
in  { packages = [ makePath ".", makeDetails { ... } ] }