### Running Documentation Examples as Tests with `nickel test` Source: https://nickel-lang.org/user-manual/command-line-interface Shows how `nickel test` extracts and runs markdown code blocks tagged with 'nickel' as tests. This example demonstrates a failing test due to a type error. ```nickel { foo | Number | doc m%" This is my field named foo. ## Examples ```nickel 1 + "2" ``` "% } ``` -------------------------------- ### Single-line String Example Source: https://nickel-lang.org/user-manual/syntax.md Demonstrates the basic usage of single-line strings. ```nickel > "Hello, World!" "Hello, World!" ``` -------------------------------- ### Nix Symbolic String Example Source: https://nickel-lang.org/user-manual/syntax.md This example demonstrates a symbolic string used in a Nix configuration written in Nickel. It interpolates Nix package references within a shell command. ```nickel { args = [ "-c", nix-s%" %{inputs.gcc}/bin/gcc %{inputs.hello} -o hello %{inputs.coreutils}/bin/mkdir -p $out/bin %{inputs.coreutils}/bin/cp hello $out/bin/hello "%, ], .. } ``` -------------------------------- ### Multiline String Example Source: https://nickel-lang.org/user-manual/syntax.md Shows how to define and use multiline strings, preserving newlines and indentation. ```nickel > m%" ... "%m%"Well, if this isn't a multiline string? Yes it is, indeed it is" ``` -------------------------------- ### Dynamic Typing Example Source: https://nickel-lang.org/user-manual/typing Demonstrates a basic configuration with dynamic typing. Errors will be caught at runtime if types are incompatible. ```nickel { name = "hello", version = "0.1.1", fullname = if std.is_number version then "hello-v%{std.string.from_number version}" else "hello-%{version}", } ``` -------------------------------- ### Arrow (Function) Type Examples Source: https://nickel-lang.org/user-manual/typing Provides examples of defining functions with different parameter counts and return types. ```nickel { increment : Number -> Number = fun x => x + 1, make_path : String -> String -> String -> String = fun basepath filename ext => "%{basepath}/%{filename}.%{ext}", } ``` -------------------------------- ### Record Type Example Source: https://nickel-lang.org/user-manual/typing Illustrates defining and accessing fields of a record with static types. ```nickel let pair : {fst: Number, snd: String} = {fst = 1, snd = "a"} in pair.fst : Number ``` -------------------------------- ### Example Usage of split Function Source: https://nickel-lang.org/user-manual/correctness Demonstrates calling the `split` function with an array of key-value pairs and shows the expected output. ```nickel { keys = [ "bar", "foo" ], values = [ 2, 1 ], } > split [ {key = "firewall", value = true}, {key = "grsec", value = false}, {key = "iptables", value = true}, ] { keys = [ "iptables", "grsec", "firewall" ], values = [ true, false, true ], } ``` -------------------------------- ### Array Type Example Source: https://nickel-lang.org/user-manual/typing Demonstrates the usage of the Array type constructor for nested arrays and flattening. ```nickel let x : Array (Array Number) = [[1,2], [3,4]] in std.array.flatten x : Array Number ``` -------------------------------- ### Record to Dictionary Subtyping Example Source: https://nickel-lang.org/user-manual/typing Shows how a record with specific number fields can be treated as a dictionary of numbers when expected by a function like std.record.map. ```nickel let occurrences : {a : Number, b : Number, c : Number} = {a = 1, b = 3, c = 0} in std.record.map (fun char count => count + 1) occurrences : {_ : Number} ``` -------------------------------- ### Example: Merging UDP and TCP Firewall Rules Source: https://nickel-lang.org/user-manual/merging Demonstrates merging two records containing firewall open port configurations for UDP and TCP protocols. ```nickel # file: udp.ncl { # same as firewall = {open_ports = {udp = [...]}}, firewall.open_ports.udp = [12345,12346], } # file: tcp.ncl { # same as firewall = {open_ports = {tcp = [...]}}, firewall.open_ports.tcp = [23, 80, 443], } # firewall.ncl let udp = import "udp.ncl" in let tcp = import "tcp.ncl" in udp & tcp ``` -------------------------------- ### Dictionary Type Example Source: https://nickel-lang.org/user-manual/typing Shows how to use a dictionary type with unknown field names but a known value type. ```nickel let occurrences : {_: Number} = {a = 1, b = 3, c = 0} in std.record.map (fun char count => count + 1) occurrences : {_ : Number} ``` -------------------------------- ### Closed Record Contract Example Source: https://nickel-lang.org/user-manual/contracts Demonstrates that by default, record contracts are closed and reject configurations with extra fields. ```nickel > let Contract = {foo | String} > {foo = "a", bar = 1} | Contract error: contract broken by a value extra field `bar` [...] ``` -------------------------------- ### Equality Comparisons Source: https://nickel-lang.org/user-manual/syntax.md Provides examples of equality (==) and inequality (!=) comparisons between different values in Nickel, highlighting type sensitivity. ```nickel > 1 == 1 true ``` ```nickel > 5 == 5.0 true ``` ```nickel > "Hello" == "Hello" true ``` ```nickel > "Hello" != "World" true ``` ```nickel > 5 == "Hello" false ``` ```nickel > true == "true" false ``` -------------------------------- ### Example Nickel Manifest File Source: https://nickel-lang.org/user-manual/package-management Defines project metadata and dependencies for Nickel package management. Use this to declare external libraries your project relies on. ```nickel { name = "my-github-workflow", version = "1.0.0", authors = ["Me "], minimal_nickel_version = "1.12.0", dependencies = { gh = 'Index { package = "github:nickel-lang/github-workflow", version = "1.0.0" } }, } | std.package.Manifest ``` -------------------------------- ### Dynamic Typing with Functions Example Source: https://nickel-lang.org/user-manual/typing Demonstrates a function using dynamic typing that leads to a type error due to incorrect argument types. ```nickel let filter = fun pred l => std.array.fold_left (fun acc x => if pred x then acc @ [x] else acc) [] l in filter (fun x => if x % 2 == 0 then x else -1) [1,2,3,4,5,6] ``` -------------------------------- ### Default Value Example Source: https://nickel-lang.org/user-manual/merging Illustrates how a `default` annotation provides a base value that can be overridden by merging. ```nickel let base = { firewall.enabled | default = true, firewall.type | default = "iptables", firewall.open_ports | default = [21, 80, 443], } in let patch = { firewall.enabled = false, server.host.options = "TLS", } in base & patch ``` -------------------------------- ### Nickel Boolean Operators Source: https://nickel-lang.org/user-manual/syntax.md Examples of Nickel's logical AND (&&), OR (||), and NOT (!) operators, demonstrating their behavior and lazy evaluation. ```nickel true && false false ``` ```nickel false || true true ``` ```nickel ! true false ``` -------------------------------- ### Symbolic String Desugaring Example 1 Source: https://nickel-lang.org/user-manual/syntax.md Shows how a basic symbolic string with interpolated values is desugared into a record containing fragments and prefix information. ```nickel > mytag-s%"I'm %{"symbolic"} with %{"fragments"}"% ``` ```json { fragments = [ "I'm ", "symbolic", " with ", "fragments" ], prefix = 'mytag, tag = 'SymbolicString, } ``` -------------------------------- ### Runtime Contract Check Example Source: https://nickel-lang.org/user-manual/contracts Demonstrates successful and failed runtime contract checks. A 'Number' contract is applied, showing the expected output for a valid number and an error for an invalid type. ```nickel > 1 + 1 | Number 2 ``` ```nickel > "a" | Number error: contract broken by a value [...] ``` -------------------------------- ### Testing for Expected Output Source: https://nickel-lang.org/user-manual/command-line-interface Illustrates how to specify expected output for a test case using the `# => ` comment. This example shows a test that fails because the actual output (2) does not match the expected output (3). ```nickel { foo | Number | doc m%" This is my field named foo. ## Examples ```nickel 1 + 1 # => 3 ``` "% } ``` -------------------------------- ### Symbolic String Desugaring Example 2 Source: https://nickel-lang.org/user-manual/syntax.md Demonstrates the desugaring of a symbolic string that interpolates a record and a literal number, illustrating how different types are handled. ```nickel > let terraform_computed_field = { tag = 'TfComputed, resource = "foo", field = "id", } > tf-s%"id: %{terraform_computed_field}, port: %{5}"% ``` ```json { fragments = [ "id: ", { field = "id", resource = "foo", tag = 'TfComputed, }, ", port: ", 5 ], prefix = 'tf, tag = 'SymbolicString, } ``` -------------------------------- ### Enum Type Example Source: https://nickel-lang.org/user-manual/typing Defines and uses an enumeration with multiple alternatives, including types for variants. ```nickel let protocol_id : [| 'http, 'ftp, 'sftp |] -> [| 'Ok Number, 'Error String |] = match { 'http => 'Ok 1, 'ftp => 'Ok 2, 'sftp => 'Error "SSL isn\'t supported", } in protocol_id 'http ``` -------------------------------- ### Contract Violation Example Output Source: https://nickel-lang.org/user-manual/merging Shows the error output when a merged configuration violates a custom contract, specifically when a port number is less than the required minimum. ```text error: contract broken by the value of `port` ┌─ example.ncl:27:17 │ 22 │ | GreaterThan 1024 │ ---------------- expected type · 27 │ port | Port = 80, │ ^^ applied to this expression ``` -------------------------------- ### Exporting a Partial Record (Error Example) Source: https://nickel-lang.org/user-manual/modular-configurations Demonstrates the error that occurs when attempting to export a partial Nickel configuration that is missing a required field ('ip' in this case). This highlights the need for all fields to be defined before export. ```bash $ nickel export machine.ncl error: missing definition for `ip` ┌─ machine.ncl:2:3 │ 1 │ ╭ { 2 │ │ ip, │ │ ^^ required here 3 │ │ cmd = "ssh -p 8070 user@%{ip}", 4 │ │ } │ ╰─' in this record ``` -------------------------------- ### Recursive Overriding in Firewall Example Source: https://nickel-lang.org/user-manual/merging Demonstrates recursive overriding by modifying a default value (`firewall.open_proto.ftp`) and observing the automatic update of a dependent field (`firewall.open_ports`). ```nickel let security = { firewall.open_proto.http | default = true, firewall.open_proto.https | default = true, firewall.open_proto.ftp | default = true, firewall.open_ports = [] @ (if firewall.open_proto.ftp then [21] else []) @ (if firewall.open_proto.http then [80] else []) @ (if firewall.open_proto.https then [443] else []), } in # => security.firewall.open_ports = [21, 80, 443] security & { firewall.open_proto.ftp = false } # => firewall.open_ports = [80, 443] ``` -------------------------------- ### Delayed Contracts and Laziness Example Source: https://nickel-lang.org/user-manual/contracts Illustrates lazy evaluation with delayed contracts, showing that fields causing contract violations are not evaluated until accessed. ```nickel let config = { fail | std.FailWith "ooch" = null, data | doc "Some information" = 42 } > :query config data * documentation: Some information > config.fail error: contract broken by the value of `fail` ooch [...] ``` -------------------------------- ### Exported Recursive Record Configuration Source: https://nickel-lang.org/user-manual/modular-configurations Shows the exported result of the recursive record example, illustrating that the 'cmd' field in 'new' has been updated based on the overridden 'ip' field. ```json { "old": { "ip": "1.1.1.1" "cmd": "ssh -p 8070 user@1.1.1.1", }, "new": { "ip": "198.162.0.1" "cmd": "ssh -p 8070 user@198.162.0.1", }, } ``` -------------------------------- ### Dictionary Subtyping Example Source: https://nickel-lang.org/user-manual/typing Demonstrates dictionary subtyping, where a dictionary containing records with a specific field is accepted where a dictionary of dictionaries is expected. This relies on the subtyping relationship between the inner record and dictionary types. ```nickel let block : _ = let dict_of_records : { _ : {a : Number}} = {r = {a = 5}} in let inject_b : { _ : {_ : Number}} -> { _ : {_ : Number}} = std.record.map (fun _ x => std.record.insert "b" 5 x) in inject_b dict_of_records in block ``` -------------------------------- ### Record Contract with Field Definitions and Merging Source: https://nickel-lang.org/user-manual/contracts Demonstrates defining a record contract with fields and merging it with a record value. Shows an example of a merge error when boolean fields are not equal. ```nickel let Secure = { must_be_very_secure | Bool = true, data | String, } let value = {data = "", must_be_very_secure = false} value | Secure ``` ```nickel let Secure = { must_be_very_secure | Bool = true, data | String, } std.serialize 'Json ({data = ""} | Secure) ``` -------------------------------- ### Array Subtyping Example Source: https://nickel-lang.org/user-manual/typing Illustrates array subtyping where an array of records with a specific field is accepted where an array of dictionaries is expected. This relies on the subtyping relationship between the record and dictionary types. ```nickel let block : _ = let array_of_records : Array {a : Number} = [{a = 5}] in let inject_b : Array {_ : Number} -> Array {_ : Number} = std.array.map (fun a => std.record.insert "b" 5 a) in inject_b array_of_records in block ``` -------------------------------- ### Overriding a Package Version in Nix Source: https://nickel-lang.org/user-manual/modular-configurations Illustrates a common pattern in Nix for attempting to override a package's version. This example shows a naive approach that often fails because it only overrides the final version field, not other version-dependent fields. ```nix wasm_bindgen_cli = pkgs.wasm-bindgen-cli // {version = wasm_bindgen_fixed_version;} ``` -------------------------------- ### Multiline Tests Source: https://nickel-lang.org/user-manual/command-line-interface Explains how to define multiple tests within a single code block using the 'multiline' label. Tests are separated by blank lines, allowing for concise documentation of several examples. ```nickel { foo | Number | doc m%" This is my field named foo. ## Examples ```nickel multiline 1 + "2" # => error: has type String, but Number was expected 1 + 1 # => 2 1 + 2 # => 3 ``` "% } ``` -------------------------------- ### Configuration as a Function Source: https://nickel-lang.org/user-manual/modular-configurations Illustrates how to turn an entire configuration into a function, allowing parameters to be passed at deployment time. This pattern is analogous to how Nix packages are defined, where dependencies are passed as arguments. ```nickel fun {param1, param2, ..} => { # your config } ``` -------------------------------- ### FooOf Contract Implementation with apply Source: https://nickel-lang.org/user-manual/contracts Re-implements a parametrized contract `FooOf` using `std.contract.apply` for delayed checks. This example illustrates how `apply` is used within custom contract implementations when the contract is expected to be applied later. ```nickel > let FooOf = fun Contract => std.contract.custom (fun label => match { 'Foo arg => 'Ok ('Foo (std.contract.apply Contract label arg)), _ => 'Error {}, } ) > 'Foo 5 | FooOf Number 'Foo 5 > 'Foo "a" | FooOf Number error: contract broken by a value [...] ``` -------------------------------- ### Row Polymorphism with Enums Example Source: https://nickel-lang.org/user-manual/typing Demonstrates row polymorphism applied to enums, where a function can handle a specific set of enum variants ('http', 'ftp') and any other variants via a catch-all case. ```nickel { port_of : forall a. [| 'http, 'ftp; a |] -> Number = match { 'http => 80, 'ftp => 21, _ => 8000, } } ``` -------------------------------- ### Importing and Composing Modules Source: https://nickel-lang.org/user-manual/modular-configurations Demonstrates how to import multiple configuration modules (network, services, volumes) and compose them into a single configuration by passing parameters to a root function. This pattern is useful for creating a unified configuration from distinct parts. ```nickel let network = import "network.ncl" in let services = import "services.ncl" in let volumes = import "volumes.ncl" in fun { ip, firewall_enabled, ipv6_enabled, httpd_enabled, openssh_version, volume_max_size, lvm_enabled, } => network { ip, firewall_enabled, ipv6_enabled } & services { httpd_enabled, openssh_version } & volumes { volume_max_size, lvm_enabled } ``` -------------------------------- ### Array Contract with Custom Predicate Source: https://nickel-lang.org/user-manual/contracts Shows how to define a custom array contract using `std.contract.from_predicate` to check if array elements meet specific criteria. An example of a contract violation is provided. ```nickel let VeryBig = std.contract.from_predicate ( fun value => std.is_number value && value >= 1000 ) [1000, 10001, 2] | Array VeryBig ``` -------------------------------- ### Split Configuration Files Source: https://nickel-lang.org/user-manual/merging Demonstrates splitting a server configuration into separate files and merging them using the '&' operator. ```nickel # file: server.ncl { host_name = "example", host = "example.org", ip_addr = "0.0.0.0", } # file: firewall.ncl { enable_firewall = true, open_ports = [23, 80, 443], } # file: network.ncl let server = import "server.ncl" in let firewall = import "firewall.ncl" in server & firewall ``` -------------------------------- ### Defining Reusable Configuration with Variables and Functions Source: https://nickel-lang.org/user-manual/modular-configurations Demonstrates how to define reusable configuration parts using variables and functions, allowing for dynamic parameterization of configuration blocks. This approach avoids copy-pasting and helps maintain consistency across similar configuration entries. ```nickel let master_ip = "192.168.1.23" in let machine = fun {ip, open_ports} => { # machine definition depending on ip and open_ports } in { ip = master_ip, cmd = "ssh -p 8070 user@%{master_ip}", client1 = machine {ip = "0.0.0.0", open_ports = [22]}, client2 = machine {ip = "1.1.1.1", open_ports = [80]}, } ``` -------------------------------- ### Record Row Polymorphism Solution Example Source: https://nickel-lang.org/user-manual/typing Shows the corrected type annotation using row polymorphism (`forall a b. { total : Number; a }`) to allow functions to accept records with a 'total' field and any other fields. ```nickel ( let add_total : forall a b. { total : Number; a } -> { total : Number; b } -> Number = fun r1 r2 => r1.total + r2.total in let r1 = { jan = 200, feb = 300, march = 10, total = jan + feb } in let r2 = { aug = 50, sept = 20, total = aug + sept } in let r3 = { may = 1300, june = 400, total = may + june } in { partial1 = add_total r1 r2, partial2 = add_total r2 r3, } ) : { partial1 : Number, partial2 : Number } ``` -------------------------------- ### Importing and Calling split Function Source: https://nickel-lang.org/user-manual/correctness Shows how to import the `split` function from `lib.ncl` and call it within a configuration file. ```nickel # config.ncl let {split} = import "lib.ncl" in split [{key = "foo", value = 1}, {key = "bar", value = 2}] ``` -------------------------------- ### Documenting Imports with `nickel doc` Source: https://nickel-lang.org/user-manual/command-line-interface Demonstrates how `nickel doc` recursively documents fields from imported modules. Only the main entry point needs to be documented. ```nickel { main_field | doc "My main field", sub_record | doc "Other stuff" = import "inner.ncl", } ``` ```nickel { inner_field | doc "My inner field", } ``` -------------------------------- ### Calling Statically Typed `filter` from Dynamic Code Source: https://nickel-lang.org/user-manual/typing Demonstrates calling the statically typed `std.array.filter` function from a dynamically typed context. The example shows how Nickel's contract system catches type violations at runtime, providing specific error messages. ```nickel > std.array.filter (fun x => if x % 2 == 0 then x else null) [1,2,3,4,5,6] error: contract broken by the caller of `filter` ┌─ :431:25 │ 431 │ : forall a. (a -> Bool) -> Array a -> Array a │ ---- expected return type of a function provided by the caller │ ┌─ :1:55 │ 1 │ std.array.filter (fun x => if x % 2 == 0 then x else null) [1,2,3,4,5,6] │ ---- evaluated to this expression [...] ``` -------------------------------- ### Contract Violation Example Source: https://nickel-lang.org/user-manual/contracts Illustrates a contract violation where a string is provided for a field expecting a port number. ```text $ nickel export config.ncl error: contract broken by the value of `server_port` ┌─ example.ncl:26:7 │ 16 │ server_port | Port, │ ---- expected type · 26 │ ╭ if host == "localhost" then 27 │ │ "8080" │ │ ------ evaluated to this expression 28 │ │ else 29 │ │ 80, │ ╰──────────^ applied to this expression │ ┌─ (generated by evaluation):1:1 │ 1 │ "8080" │ ------ evaluated to this value ``` -------------------------------- ### Polymorphic function with type annotation Source: https://nickel-lang.org/user-manual/syntax.md An example of a polymorphic function 'f' with a type annotation, applied to a number and then type-checked. ```nickel > let f : forall a. a -> a = fun x => x in (f 5 : Number) 5 ``` -------------------------------- ### Function definition and application Source: https://nickel-lang.org/user-manual/syntax.md Define functions using `fun => ` and call them by providing arguments after the function. ```nickel > (fun a b => a + b) 1 2 3 ``` ```nickel > let add = fun a b => a + b in add 1 2 3 ``` ```nickel > let add = fun a b => a + b in let add1 = add 1 in add1 2 3 ``` -------------------------------- ### Importing a Nickel File Source: https://nickel-lang.org/user-manual/syntax.md Demonstrates importing a Nickel file using the 'import' keyword and accessing its members. The file extension determines the format. ```nickel > let lib = import "lib.ncl" in lib.base64_encode [01, 02, 03] ``` -------------------------------- ### Dynamic Typing Error Example Source: https://nickel-lang.org/user-manual/typing Illustrates a runtime type error in dynamic typing where a string is added to a number. ```nickel { name = "hello", version = "0.1.1", fullname = if std.is_number version then "hello-v%{std.string.from_number version}" else "hello-%{version + 1}", } ``` -------------------------------- ### Extend Configuration with New Fields Source: https://nickel-lang.org/user-manual/merging Shows how to extend an existing configuration by merging it with a record containing new fields. ```nickel # file: safe-network.ncl let base = import "network.ncl" in base & {use_iptables = true} ``` -------------------------------- ### Defining a Reusable Configuration Module with Metadata Source: https://nickel-lang.org/user-manual/modular-configurations Shows how to structure a configuration as a module using records and metadata. Fields like 'inputs' and 'local' are marked with 'not_exported' to indicate they are for internal use or setting by consumers, while others form the final configuration. ```nickel { inputs | not_exported = { foo | String | doc "Doc of foo", bar | Number | doc "Doc of bar", unused | Bool | optional, }, local | not_exported = { computed = std.string.lowercase inputs.foo, }, some_config_option = inputs.bar + 1, other_option = std.string.join " " ["Hello", local.computed], last_option = "values are %{local.computed} and %{inputs.bar}", } ``` -------------------------------- ### Multiline String Indentation Stripping Source: https://nickel-lang.org/user-manual/syntax.md Example of how indentation is stripped from multiline strings, ignoring leading/trailing empty lines and common indentation. ```nickel > m%" This line has no indentation. This line is indented. This line is even more indented. This line has no more indentation. "% "This line has no indentation.\n This line is indented.\n This line is even more indented.\nThis line has no more indentation." ``` -------------------------------- ### Sample YAML Data Structure Source: https://nickel-lang.org/user-manual/tutorial This is a sample of the desired YAML output structure for user data, illustrating fields like name, is-admin, and ssh-keys. ```yaml users: - name: Aisha is-admin: true ssh-keys: - AAAAApqCA8oKAB5S/47f...... aisha@work - name: Violet extra-groups: - accounting ``` -------------------------------- ### Nickel CLI Help Source: https://nickel-lang.org/user-manual/command-line-interface Displays general help information for the Nickel CLI and specific command help. ```bash $ nickel help The Nickel interpreter CLI Usage: nickel [OPTIONS] Commands: eval Evaluates a Nickel program and pretty-prints the result # etc. ``` ```bash $ nickel help eval Evaluates a Nickel program and pretty-prints the result Usage: nickel eval [OPTIONS] [FILES]... [-- ...] Arguments: # etc. ``` -------------------------------- ### Using Contract Application with Type Annotations Source: https://nickel-lang.org/user-manual/typing Demonstrates how contract application can be used to satisfy type annotations with custom contracts, treating them as opaque types. ```nickel (let p | Port = 10 - 1 in let id = fun x => x in id p ) : Port ``` -------------------------------- ### Test Field Value Validation of NumberBoolDict Contract Source: https://nickel-lang.org/user-manual/contracts This example demonstrates the `NumberBoolDict` contract correctly identifies and reports an error when a field value is not a boolean. ```nickel let config | NumberBoolDict = { "0" | doc "Some information" = "not a boolean", } config."0" ``` -------------------------------- ### Test Field Name Validation of NumberBoolDict Contract Source: https://nickel-lang.org/user-manual/contracts This example shows the `NumberBoolDict` contract correctly identifies and reports an error when a field name is not a number. ```nickel let config | NumberBoolDict = { not_a_number = false, "0" | doc "Some information" = false, } config."0" ``` -------------------------------- ### Higher-Order Function Contract Violation: Caller Error Source: https://nickel-lang.org/user-manual/contracts Example of a contract violation with a higher-order function where the provided function parameter does not meet the expected type. ```nickel let apply_fun | (Number -> Number) -> Number = fun f => f 0 in apply_fun (fun x => "a") error: contract broken by the caller ┌─ :1:29 │ 1 │ let apply_fun | (Number -> Number) -> Number = fun f => f 0 in │ ------ expected return type of a function provided by the caller 2 │ apply_fun (fun x => "a") │ --- evaluated to this expression │ ┌─ (generated by evaluation):1:1 │ 1 │ "a" │ --- evaluated to this value [...] ``` -------------------------------- ### Statically Typed Value in Static Block Source: https://nickel-lang.org/user-manual/typing A simple example showing a statically typed value being correctly used within a statically typed block. ```nickel let x = 1 in (1 + x : Number) ``` -------------------------------- ### Static Typing Annotations Source: https://nickel-lang.org/user-manual/typing Shows how to use type annotations (`:`) for let bindings, record fields, and inline expressions to enable static type checking. ```nickel # Let binding let f : Number -> Bool = fun x => x % 2 == 0 in # Record field let r = { count : Number = 2354.45 * 4 + 100, } in # Inline 1 + ((if f 10 then 1 else 0) : Number) ``` -------------------------------- ### Querying Specific Configuration Fields Source: https://nickel-lang.org/user-manual/modular-configurations Demonstrates querying a specific field (`path_libc`) within a Nickel configuration to retrieve its contract, default value, and documentation. ```bash $ nickel query examples/config-gcc/config-gcc.ncl path_libc ``` -------------------------------- ### Merging with Force Priority Source: https://nickel-lang.org/user-manual/syntax.md The 'force' metadata annotation indicates the highest merge priority. This example shows that a 'force' value overrides any other value for the same field during merging. ```nickel > {foo | force = 1, bar = foo + 1} & {foo = 2} { bar = 2, foo | force = 1, } ``` -------------------------------- ### Generating API Documentation with `nickel doc` Source: https://nickel-lang.org/user-manual/command-line-interface Generates markdown API documentation from metadata and contract annotations in Nickel source files. ```nickel { foo | Number | doc "This is my field named foo." } ``` ```bash nickel doc main.ncl ``` ```markdown # `foo` - `foo | Number` This is my field named foo. ``` -------------------------------- ### Test Laziness of NumberBoolDict Contract Source: https://nickel-lang.org/user-manual/contracts This example demonstrates that the `NumberBoolDict` contract preserves laziness, as accessing a valid field does not trigger evaluation of other potentially failing fields. ```nickel let config | NumberBoolDict = { "1" | std.FailWith "ooch" = null, # same as our previous "fail" "0" | doc "Some information" = true, } config."0" ``` -------------------------------- ### Importing Files with Explicit Format Tags Source: https://nickel-lang.org/user-manual/syntax.md Shows how to import files and explicitly specify their format using enum tags like 'Text' when the file extension is not standard or needs to be overridden. ```nickel > import "test.html" as 'Text ``` -------------------------------- ### Querying Configuration Fields Source: https://nickel-lang.org/user-manual/modular-configurations Shows how to use the `nickel query` subcommand to extract information and documentation from a Nickel configuration file. This command can inspect the structure and details of defined fields. ```bash $ nickel query examples/config-gcc/config-gcc.ncl ``` -------------------------------- ### Applying Contract Annotation to split Function Source: https://nickel-lang.org/user-manual/correctness Demonstrates how to apply a contract annotation to the `split` function, which is checked at runtime. ```nickel split | forall a. Array {key: String, value: a} -> {keys: Array String, values: Array a} = # etc. ``` -------------------------------- ### Runtime Error Example Source: https://nickel-lang.org/user-manual/correctness Illustrates a dynamic type error that occurs when the `split` function is called with incorrect argument types, highlighting limitations of contract annotations. ```nickel error: dynamic type error ┌─ lib.ncl:8:33 │ 8 │ keys = acc.keys @ pair.key, │ ^^^^^^^^ this expression has type String, but Array was expected │ ┌─ { total : Number } -> Number = fun r1 r2 => r1.total + r2.total in let r1 = { jan = 200, feb = 300, march = 10, total = jan + feb } in let r2 = { aug = 50, sept = 20, total = aug + sept } in let r3 = { may = 1300, june = 400, total = may + june } in { partial1 = add_total r1 r2, partial2 = add_total r2 r3, } ) : { partial1 : Number, partial2 : Number } ``` -------------------------------- ### Querying a Non-Function Value Source: https://nickel-lang.org/user-manual/modular-configurations Illustrates that `nickel query` can inspect non-function values, revealing their available fields. This example shows querying a record defined with a `let` binding. ```nickel let example1 = let value = 1 in {left = "a", right = 1} > :query example1 Available fields • left • right ``` -------------------------------- ### Querying Documentation for a Field Source: https://nickel-lang.org/user-manual/merging Shows how to attach documentation to a field using the `doc` keyword and then query it using `nickel query`. The documentation is propagated through merging. ```nickel # config.ncl { foo | doc "Some documentation" | default = {} } & { foo.field = null, } ``` ```shell $ nickel query --field foo config.ncl • documentation: Some documentation Available fields • field ``` -------------------------------- ### Anonymous Function Example Source: https://nickel-lang.org/user-manual/types-vs-contracts Short anonymous functions often do not require explicit annotations, especially when used within a typed block or passed as arguments to higher-order functions that have contracts. ```nickel std.array.map (fun x => x + 1) [1,2,3] ``` -------------------------------- ### Using the Optional Annotation in Contracts Source: https://nickel-lang.org/user-manual/syntax.md The 'optional' annotation signifies that a field within a record contract is not mandatory. This example defines a contract and then attempts to create a record that omits an optional field. ```nickel > let Contract = { foo | Number, bar | Number | optional, } > let value | Contract = {foo = 1} > value { foo | Number = 1, } > {bar = 1} | Contract error: missing definition for `foo` [...] ``` -------------------------------- ### Nested Record Creation with Piecewise Syntax Source: https://nickel-lang.org/user-manual/syntax.md Demonstrates creating nested records using piecewise syntax, where fields are accessed or defined using dot notation. ```nickel > { a = { b = 1 } } { a = { b = 1, }, } ``` ```nickel > { a.b = 1 } { a = { b = 1, }, } ``` ```nickel > { a.b = 1, a.c = 2, b = 3} { a = { b = 1, c = 2, }, b = 3, } ``` -------------------------------- ### Custom Contract Blaming the Worse Value Source: https://nickel-lang.org/user-manual/contracts An example of a custom contract that checks two inner values and programmatically manipulates the blame location to point to the worse of the two failing values. ```nickel let SmallNumber = std.contract.from_predicate (fun x => (std.is_number x) && x < 100) in let TwoNumbers = std.contract.custom (fun label value => std.contract.check { a, b } label value |> match { 'Error e => 'Error e, 'Ok { a, b } => [std.contract.check SmallNumber label a, std.contract.check SmallNumber label b] |> match { ['Ok x, 'Ok y] => 'Ok { a = x, b = y }, ['Ok _, 'Error e] => 'Error e, ['Error e, 'Ok _] => 'Error e, ['Error { blame_location = a_loc, ..}, 'Error { blame_location = b_loc, ..}] => 'Error { message = "they were both bad, but this one was worse", blame_location = if a >= b then a_loc else b_loc } } } ) in { a = 100, b = 101, } | TwoNumbers ``` -------------------------------- ### Customizing Greeter in Hello Service Source: https://nickel-lang.org/user-manual/merging Demonstrates how to override a default value in a Nickel configuration to customize output. The `greeter` field is changed from 'world' to 'country'. ```nickel { greeter | String | not_exported | default = "world", systemd.services.hello = { wantedBy = ["multi-user.target"], serviceConfig.ExecStart = "/usr/bin/hello -g'Hello, %{greeter}!'", }, } ``` ```shell $ nickel export <<< '(import "hello-service.ncl") & {greeter = "country"}' { "systemd": { "services": { "hello": { "serviceConfig": { "ExecStart": "/usr/bin/hello -g'Hello, country!'" }, "wantedBy": [ "multi-user.target" ] } } } } ``` -------------------------------- ### Defining a Partial Record with Recursive Fields Source: https://nickel-lang.org/user-manual/modular-configurations Shows a Nickel configuration snippet for a machine, defining an 'ip' field and a 'cmd' field that recursively depends on 'ip'. This demonstrates a partial configuration that requires 'ip' to be defined later. ```nickel # machine.ncl { ip, cmd = "ssh -p 8070 user@%{ip}", } ``` -------------------------------- ### Or-Pattern Matching Source: https://nickel-lang.org/user-manual/syntax.md Shows how to use 'or' to specify multiple alternative patterns that must bind the same variables. ```nickel ('Foo x) or ('Bar x) ``` -------------------------------- ### Exporting with Customize Mode Source: https://nickel-lang.org/user-manual/command-line-interface Exports a Nickel configuration, passing parameters to customize mode. Parameters are assigned after the '--' separator. ```nickel { params | not_exported = { environment | [| 'dev, 'prod |], mock_db | Bool, }, test_string = "env=${params.environment}, mock_db=${params.mock_db}", } ``` ```bash $ nickel export main.ncl -- params.environment=\'dev params.mock_db=true { "test_string": "env=dev, mock_db=true" } ~ ``` -------------------------------- ### Using `any_of` for Schema Definition Source: https://nickel-lang.org/user-manual/syntax.md Shows how to define a schema using `std.contract.any_of` to allow a field to accept multiple types, suitable for serialization. ```nickel let Schema = { size | std.contract.any_of [String, Number], .. } in { size = "1MB" } | Schema ``` -------------------------------- ### Typed Block Function Annotation (Polymorphic) Source: https://nickel-lang.org/user-manual/types-vs-contracts Polymorphic functions within a typed block must be annotated, as the typechecker does not infer polymorphic types. This example shows a complex polymorphic function signature. ```nickel > let foo : Number = let ev : ((Number -> Number) -> Number) -> Number -> Number = fun f x => f (std.function.const x) in ev (fun f => f 0) 1 ``` -------------------------------- ### Nickel Comparison Operators Source: https://nickel-lang.org/user-manual/syntax.md Illustrates the usage of comparison operators for checking equality, inequality, and order between numbers in Nickel. ```nickel 5 == 5 ``` ```nickel 5 != 4 ``` ```nickel 2 < 3 ``` ```nickel 1 > -5 ``` ```nickel 1 >= 1 ``` ```nickel -1 <= 6 ``` -------------------------------- ### Nickel Basic Arithmetic Operators Source: https://nickel-lang.org/user-manual/syntax.md Demonstrates the use of basic arithmetic operators for addition, subtraction, multiplication, division, and modulo in Nickel. ```nickel 1 + 2 = 3 ``` ```nickel 1 - 2 = -1 ``` ```nickel 1 * 2 = 2 ``` ```nickel 1 / 2 = 0.5 ``` ```nickel 5 % 3 = 2 ``` -------------------------------- ### Type Error Example: Incompatible Rows Declaration Source: https://nickel-lang.org/user-manual/correctness Illustrates a type error where a field's expected type (Array String) conflicts with its found type (String) due to incorrect usage with `fold`. ```nickel error: incompatible rows declaration ┌─ lib.ncl:13:9 │ 13 │ pairs │ ^^^^^ this expression │ = Expected an expression of a record type with the row `key: Array _a` = Found an expression of record type with the row `key: String` = Could not match the two declarations of `key` error: while typing field `key`: incompatible types = Expected an expression of type `Array _a` = Found an expression of type `String` = These types are not compatible ``` -------------------------------- ### Listing Available Fields in Customize Mode Source: https://nickel-lang.org/user-manual/command-line-interface Lists the fields available for assignment or overriding in a Nickel configuration for customize mode. ```bash $ nickel export main.ncl -- list Input fields: - params.environment: <[| 'dev, 'prod |]> - params.mock_db: Overridable fields (require `--override`): - test_string ``` -------------------------------- ### Record Subtyping Example Source: https://nickel-lang.org/user-manual/typing Shows record subtyping where a record containing a nested record with a specific field is accepted where a record containing a nested dictionary is expected. This relies on the subtyping relationship between the nested record and dictionary types. ```nickel let block : _ = let record_of_records : {a: {b : Number}} = {a = {b = 5}} in let inject_c_in_a : {a : {_ : Number}} -> {a : {_ : Number}} = fun x => {a = std.record.insert "c" 5 (std.record.get "a" x)} in inject_c_in_a record_of_records in block ``` -------------------------------- ### Dictionary Contract Usage Source: https://nickel-lang.org/user-manual/contracts Demonstrates how to use a dictionary contract to define a record with string keys and values satisfying a specific contract (Number in this case). ```nickel let occurrences | {_: Number} = {a = 2, b = 3, "!" = 5, "^" = 1} in occurrences."!" ``` -------------------------------- ### Defining and Using a Custom Contract as a Type Source: https://nickel-lang.org/user-manual/typing Defines a 'Port' contract and attempts to use it in a type annotation. This demonstrates the syntax but highlights typechecker limitations. ```nickel let Port = std.contract.from_predicate (fun value => std.is_number value && value % 1 == 0 && value >= 0 && value <= 65535) in (10 - 1 : Port) ``` -------------------------------- ### String Interpolation with Variables Source: https://nickel-lang.org/user-manual/syntax.md Demonstrates interpolating a variable into a string. ```nickel > let h = "Hello" in "%h% World" "Hello World" ``` -------------------------------- ### Record Type with Dynamic Tail Source: https://nickel-lang.org/user-manual/syntax.md Shows how a record literal can be parsed as a record type even if a field's type annotation is a dynamic identifier (like `MyDyn`), as long as other record type conditions are met. The example uses a let-bound function for `MyDyn`. ```nickel > let MyDyn = fun label value => value in {foo = 1, bar | MyDyn = "foo"} : {foo : Number, bar : MyDyn} { bar | MyDyn = "foo", foo = 1, } ``` -------------------------------- ### Enum Widening and Type Inference Source: https://nickel-lang.org/user-manual/typing Illustrates how Nickel's type inference can handle enum widening implicitly, allowing a more specific enum type to be compatible with a wider one. This example shows a case that fails with explicit typing but passes when type inference is allowed. ```nickel ( let foo : [| 'Foo Number |] = 'Foo 5 in foo |> match { 'Foo x => x, 'Bar x => x, } ) : _ ``` ```nickel > ( let foo = 'Foo 5 in foo |> match { 'Foo x => x, 'Bar x => x, } ) : _ 5 ```