Adding dollar sign (apply) to nix
Table of Contents
Reading time: 1 minute
Back Home.
This post is very low quality for comedic effect.
1. A detailed list of instructions
Take one nix, apply this patch1:
What does this do? It adds a new token $
to the nix languages parser and exposes
it as __dollar
, essentially by copying the way this works for __lessThan
.
Hack on your nix:
nix develop ./bootstrap.sh ./configure $configureFlags --prefix=$(pwd)/outputs/out make -j $NIX_BUILD_CORES outputs/out/bin/nix repl
Now in the nix repl
that just opened:
nix-repl> __dollar = x: y: builtins.foldl' (a: b: a b) x y
This makes $
an infix operator that’s essentially just a generic apply.
Now just create a toy example to demonstrate:
nix-repl> concat = x: y: z: (x + y + z) nix-repl> concat $ ["literally" " " "dollar sign"]
And your repl will say:
"literally dollar sign"
Tadaa! That’s all it takes to add the $
operator to nix, just like Haskell.
The end \(\text{\\(^ヮ^)/}\)
—
Back Home.
Footnotes:
1
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 201370b90..4b26af623 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -353,6 +353,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err %left AND %nonassoc EQ NEQ %nonassoc '<' '>' LEQ GEQ +%nonassoc '$' DOL %right UPDATE %left NOT %left '+' '-' @@ -411,6 +412,8 @@ expr_op | expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprCall(makeCurPos(@2, data), new ExprVar(data->symbols.create("__lessThan")), {$3, $1})); } | expr_op '>' expr_op { $$ = new ExprCall(makeCurPos(@2, data), new ExprVar(data->symbols.create("__lessThan")), {$3, $1}); } | expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprCall(makeCurPos(@2, data), new ExprVar(data->symbols.create("__lessThan")), {$1, $3})); } + | expr_op '$' expr_op { $$ = new ExprCall(makeCurPos(@2, data), new ExprVar(data->symbols.create("__dollar")), {$1, $3}); } + | expr_op DOL expr_op { $$ = new ExprOpNot(new ExprCall(makeCurPos(@2, data), new ExprVar(data->symbols.create("__dollar")), {$3, $1})); } | expr_op AND expr_op { $$ = new ExprOpAnd(makeCurPos(@2, data), $1, $3); } | expr_op OR expr_op { $$ = new ExprOpOr(makeCurPos(@2, data), $1, $3); } | expr_op IMPL expr_op { $$ = new ExprOpImpl(makeCurPos(@2, data), $1, $3); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ddf529b9e..00622a142 100644 --- a/src/libexpr/primops.cc ...skipping... diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 201370b90..4b26af623 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -353,6 +353,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err %left AND %nonassoc EQ NEQ %nonassoc '<' '>' LEQ GEQ +%nonassoc '$' DOL %right UPDATE %left NOT %left '+' '-' @@ -411,6 +412,8 @@ expr_op | expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprCall(makeCurPos(@2, data), new ExprVar(data->symbols.create("__lessThan")), {$3, $1})); } | expr_op '>' expr_op { $$ = new ExprCall(makeCurPos(@2, data), new ExprVar(data->symbols.create("__lessThan")), {$3, $1}); } | expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprCall(makeCurPos(@2, data), new ExprVar(data->symbols.create("__lessThan")), {$1, $3})); } + | expr_op '$' expr_op { $$ = new ExprCall(makeCurPos(@2, data), new ExprVar(data->symbols.create("__dollar")), {$1, $3}); } + | expr_op DOL expr_op { $$ = new ExprOpNot(new ExprCall(makeCurPos(@2, data), new ExprVar(data->symbols.create("__dollar")), {$3, $1})); } | expr_op AND expr_op { $$ = new ExprOpAnd(makeCurPos(@2, data), $1, $3); } | expr_op OR expr_op { $$ = new ExprOpOr(makeCurPos(@2, data), $1, $3); } | expr_op IMPL expr_op { $$ = new ExprOpImpl(makeCurPos(@2, data), $1, $3); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ddf529b9e..00622a142 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -3583,6 +3583,24 @@ static RegisterPrimOp primop_lessThan({ .fun = prim_lessThan, }); +static void prim_dollar(EvalState & state, const PosIdx pos, Value * * args, Value & v) +{ + state.forceValue(*args[0], pos); + state.forceValue(*args[1], pos); + // pos is exact here, no need for a message. + CompareValues comp(state, noPos, ""); + v.mkBool(comp(args[0], args[1])); +} + +static RegisterPrimOp primop_dollar({ + .name = "__dollar", + .args = {"e1", "e2"}, + .doc = R"( + Just like haskell :) + )", + .fun = prim_dollar, +}); + /************************************************************* * String manipulation