Git Product home page Git Product logo

Comments (14)

Gabriella439 avatar Gabriella439 commented on June 15, 2024

You can do:

$ dhall <<< '(./record ).bar'

from dhall-haskell.

PierreR avatar PierreR commented on June 15, 2024

Thanks that is very helpful.

from dhall-haskell.

PierreR avatar PierreR commented on June 15, 2024

Would it actually make sense to have a shell backend for Dhall ?

For instance if I want to store bar within a shell I can do

v=$(dhall <<< '(./record ).bar ' 2> /dev/null )

v is 2 as expected but as soon as I have a List or Optional type it gets much tricky.

PS: not that I need this right now but it looks like a good use case

from dhall-haskell.

Gabriella439 avatar Gabriella439 commented on June 15, 2024

Yeah, that is a great idea!

from dhall-haskell.

eternaleye avatar eternaleye commented on June 15, 2024

There are a few options for this:

  1. Dhall can presume bash, and emit Lists as quoted values separated by the first character in $IFS
    • This permits things like declare -a DHALL_VAL=( $(dhall ./record 2>/dev/null) )
    • Maps could be emitted as IFS-separated ["key"]="val", for use with declare -A
  2. Dhall can emit the entire declaration syntax itself, for use with eval
    • This permits representing Optionals None via unset, where (1) would suffer the semipredicate problem
  3. Emit shell functions
    • Certainly the hairiest, though possibly the most flexible
    • Requires dhall output a function defintion which, internally, may invoke eval on calling dhall to bind sub-elements
    • User must eval the root extraction
  4. As any of the above, but have some way to specify the shell to generate for

Note, however:

  1. AFAIK, no shell supports nesting of either arrays or associative arrays (maps)
  2. Some shells support only arrays, and not associative arrays
  3. Some shells support neither

A viable option for all of these cases might be to simply extract the relevant sub-portion of the Dhall expression, and use Dhall on the extracted sub-portion to extract sub-components of that later. If Dhall can emit an IFS-sparated stream of quoted keys, and can produce the length of a list, then pretty much any shell's own looping primitives can do the rest of the work.

from dhall-haskell.

Gabriella439 avatar Gabriella439 commented on June 15, 2024

Another advantage of approach 2 is that instead of using an associative array to represent records you can bind fields to environment variables of the same name. So if your dhall file were:

{ foo = 1
, bar = "ABC"
}

That would correspond to:

declare foo=1
declare bar="ABC"

I don't think we need to worry about nesting lists. If Bash doesn't have a way to represent it then we don't need to support it

Also, note that we can represent Optional using Bash arrays (keeping consistent with Dhall, which uses list notation for Optional values).

from dhall-haskell.

eternaleye avatar eternaleye commented on June 15, 2024

Well, modeling Optional using arrays has negative impacts on legibility and idiomatic use of Bash.

  • It'd require testing for [val] as [[ $#field -ne 0 ]] (cumbersome array length syntax; numeric equality is second-class) which is very unidiomatic
  • It would require extracting the field value as ${field[0]}
  • There wouldn't be a convenient syntax for using a default value if []

Expressing Optional [] as unset and [val] as set is much more natural for Bash:

  • It yields the much more idiomatic [[ -v $field ]] ("$field has a value") test, matching common use of Bash
  • The field value is simply $field if set
  • It also then permits the ${field:-default_value} syntax
  • Under set -u, accessing an unset variable is an error (helps tests ensure correctness of Bash programs using Dhall)

from dhall-haskell.

Gabriella439 avatar Gabriella439 commented on June 15, 2024

Ah, good point. Yeah, in that case we should treat Optional fields as unset variables and set fields as normal (non-array) variables

from dhall-haskell.

eternaleye avatar eternaleye commented on June 15, 2024

Another thing is that if option (2) is chosen, then Dhall can handle top-level records

  1. With second-level records as associative arrays
  2. With second-level arrays as arrays

but will have trouble with

  1. Top-level arrays (no name)
  2. Top-level values (same)
  3. Any further nesting beyond the second level (inexpressible in plain Bash)

Those issues can all be worked around - using a schema can force an error in case (1) or (2) where a record is expected, and a --name N parameter can handle non-record top-levels (though the behavior of --name N on a record type is up for debate - field prefixing?).

Furthermore, if Dhall grows a --primitive flag (that produces no output, returning 0 if the expression is a primitive, 1 if it's an aggregate, and 2 if it's malformed), bash can use that with if in order to unpack nested values so long as Dhall simply extracts their expression text.

from dhall-haskell.

Gabriella439 avatar Gabriella439 commented on June 15, 2024

Alright, I finally got around to doing this over the weekend. You can see what I have so far here:

https://github.com/Gabriel439/Haskell-Dhall-Bash-Library

I ended up deciding to provide two modes:

  • By default, the dhall-to-bash compiles to a Bash expression and only supports Text, Integer, Natural, and Bool (Note: I haven't added support for Bool yet):

    $ dhall-to-bash <<< '"ABC"'
    ABC
    $ dhall-to-bash <<< '" X "'
    $' X '
    $ dhall-to-bash <<< '1'
    1
    $ dhall-to-bash <<< '+1'
    1
    $ dhall-to-bash <<< 'True'
    true
    $ dhall-to-bash <<< 'False'
    false
  • You can optionally supply a --declare VAR flag to emit to a declare statement defining that variable compatible with eval, which allows you to additionally support Optional, List, and records

    dhall-to-bash --declare FOO <<< '"ABC\n"'
    declare -r FOO=$'ABC\n'
    $ dhall-to-bash --declare FOO <<< '1'
    declare -r -i FOO=1
    $ dhall-to-bash --declare FOO <<< '[1] : Optional Integer'
    declare -r -i FOO=1
    $ dhall-to-bash --declare FOO <<< '[[1] : Optional Integer] : Optional (Optional Integer)'
    declare -r -i FOO=1
    $ dhall-to-bash --declare FOO <<< '[] : Optional Integer'
    unset FOO
    $ dhall-to-bash --declare FOO <<< '[1, 2, 3] : List Integer'
    declare -r -a FOO=(1 2 3)
    $ dhall-to-bash --declare FOO <<< '{ bar = 1, baz = "ABC" }'
    declare -r -A FOO=([bar]=1 [baz]=ABC)

All declare statements add the -r (readonly) flag to ensure that the generated values are immutable (to match the semantics of Dhall as closely as possible) and to avoid overwriting existing variables. If users want to opt out of this they have to follow up by removing the readonly bit with an additional declare statement

Integer and Natural are declared with the -i flag to indicate that they are Bash integers

Let me know what you both think

from dhall-haskell.

PierreR avatar PierreR commented on June 15, 2024

With one dhall file that I use I have got:

Explanation: Only primitive values can be translated from Dhall to a Bash
expression

The following Dhall expression could not be translated to a Bash expression:

↳ [{ checkout = "vcsh clone [email protected]:PierreR/devbox-dotfiles.git local", path = "$HOME/.config/vcsh/repo.d/local.git" }]

Which seems to imply that a list of record cannot be translated ?

from dhall-haskell.

Gabriella439 avatar Gabriella439 commented on June 15, 2024

@PierreR: Yes, that's correct. That's mainly because it's not clear how you would represent a list of records in Bash

from dhall-haskell.

Gabriella439 avatar Gabriella439 commented on June 15, 2024

Alright, I published the first version of dhall-bash to Hackage so I'll mark this complete for now. If you have any additional requests you can open issues against the dhall-bash repository here:

https://github.com/Gabriel439/Haskell-Dhall-Bash-Library

from dhall-haskell.

PierreR avatar PierreR commented on June 15, 2024

@Gabriel439 Thanks !

from dhall-haskell.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.