Comments (14)
You can do:
$ dhall <<< '(./record ).bar'
from dhall-haskell.
Thanks that is very helpful.
from dhall-haskell.
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.
Yeah, that is a great idea!
from dhall-haskell.
There are a few options for this:
- Dhall can presume bash, and emit
List
s 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 withdeclare -A
- This permits things like
- Dhall can emit the entire declaration syntax itself, for use with
eval
- This permits representing
Optional
sNone
viaunset
, where (1) would suffer the semipredicate problem
- This permits representing
- 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
- As any of the above, but have some way to specify the shell to generate for
Note, however:
- AFAIK, no shell supports nesting of either arrays or associative arrays (maps)
- Some shells support only arrays, and not associative arrays
- 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.
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.
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.
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.
Another thing is that if option (2) is chosen, then Dhall can handle top-level records
- With second-level records as associative arrays
- With second-level arrays as arrays
but will have trouble with
- Top-level arrays (no name)
- Top-level values (same)
- 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.
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 supportsText
,Integer
,Natural
, andBool
(Note: I haven't added support forBool
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 adeclare
statement defining that variable compatible witheval
, which allows you to additionally supportOptional
,List
, and recordsdhall-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 declare
d with the -i
flag to indicate that they are Bash integers
Let me know what you both think
from dhall-haskell.
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.
@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.
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.
@Gabriel439 Thanks !
from dhall-haskell.
Related Issues (20)
- Support request for `aeson` 2.2 in `dhall` HOT 2
- dhall-to-yaml does not properly quote strings HOT 1
- Can not install dhall-lsp-server HOT 2
- Allow hnix 0.17
- Hackage build failed for dhall-toml-1.0.3
- Get back into Stackage Nightly with GHC 9.8 HOT 1
- Missing binaries in release HOT 1
- Hackage release for dhall-lsp-server HOT 1
- Build failure on GHC 9.8.1: 'Illegal invisible type variable binder'
- Report imports HOT 2
- dhall-docs: Prelude.head: empty list
- Suggesting a new construct for dealing with optional fields in Dhall defaults
- dhall-json bound on aeson can be relaxed
- Questions regarding the right strategy for upgrading to ghc-9.8
- Build failure on macos-latest stack.yaml HOT 3
- Is there a specification for dhall-to-{json,yaml} and {json,yaml}-to-dhall? HOT 2
- Pretty-printer: escape unprintable characters HOT 2
- `with` expressions regressed HOT 10
- to-directory-tree with Empty Map causes an error
- Guide to compile dhall to JS backend, wasm backend and GHCJS HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from dhall-haskell.