PageSourceSearch

https://noir-lang.org/docs/assets/js/7b720a0f.d5909f2b.js

js noir-lang.org collected 2026-10-03 22:50:17 UTC 5,560 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkdocs=globalThis.webpackChunkdocs||[]).push([[572],{9393(e,n,s){s.r(n),s.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>t,metadata:()=>o,toc:()=>c});const o=JSON.parse('{"id":"language/lambdas","title":"Lambdas","description":"Learn how to use anonymous functions in Noir programming language.","source":"@site/versioned_docs/version-v1.0.0-rc.1/language/lambdas.md","sourceDirName":"language","slug":"/language/lambdas","permalink":"/docs/v1.0.0-rc.1/language/lambdas","draft":false,"unlisted":false,"editUrl":"https://github.com/noir-lang/noir/edit/master/docs/versioned_docs/version-v1.0.0-rc.1/language/lambdas.md","tags":[],"version":"v1.0.0-rc.1","frontMatter":{"title":"Lambdas","description":"Learn how to use anonymous functions in Noir programming language.","keywords":["Noir programming language","lambda","closure","function","anonymous function"]},"sidebar":"sidebar","previous":{"title":"Mutability","permalink":"/docs/v1.0.0-rc.1/language/mutability"},"next":{"title":"Comments","permalink":"/docs/v1.0.0-rc.1/language/comments"}}');var a=s(74848),r=s(28453);const t={title:"Lambdas",description:"Learn how to use anonymous functions in Noir programming language.",keywords:["Noir programming language","lambda","closure","function","anonymous function"]},i=void 0,l={},c=[{value:"Introduction",id:"introduction",level:2},{value:"Closures",id:"closures",level:2},{value:"Passing closures to higher-order functions",id:"passing-closures-to-higher-order-functions",level:2}];function d(e){const n={admonition:"admonition",code:"code",h2:"h2",p:"p",pre:"pre",strong:"strong",...(0,r.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,a.jsxs)(n.p,{children:["Lambdas are anonymous functions. The syntax is ",(0,a.jsx)(n.code,{children:"|arg1, arg2, ..., argN| return_expression"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-rust",children:"let add_50 = |val| val + 50;\nassert(add_50(100) == 150);\n"})}),"\n",(0,a.jsx)(n.p,{children:"A block can be used as the body of a lambda, allowing you to declare local variables inside it:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-rust",children:"let cool = || {\n  let x = 100;\n  let y = 100;\n  x + y\n}\n\nassert(cool() == 200);\n"})}),"\n",(0,a.jsx)(n.h2,{id:"closures",children:"Closures"}),"\n",(0,a.jsxs)(n.p,{children:["Inside the body of a lambda, you can use variables defined in the enclosing function. Such lambdas are called ",(0,a.jsx)(n.strong,{children:"closures"}),". In this example ",(0,a.jsx)(n.code,{children:"x"})," is defined inside ",(0,a.jsx)(n.code,{children:"main"})," and is accessed from within the lambda:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-rust",children:"fn main() {\n  let x = 100;\n  let closure = || x + 150;\n  assert(closure() == 250);\n}\n"})}),"\n",(0,a.jsx)(n.h2,{id:"passing-closures-to-higher-order-functions",children:"Passing closures to higher-order functions"}),"\n",(0,a.jsx)(n.p,{children:"It may catch you by surprise that the following code fails to compile:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-rust",children:"fn foo(f: fn () -> Field) -> Field {\n f()\n}\n\nfn main() {\n  let (x, y) = (50, 50);\n  assert(foo(|| x + y) == 100); // error :(\n}\n"})}),"\n",(0,a.jsxs)(n.p,{children:["The reason is that the closure's capture environment affects its type - we have a closure that captures two Fields and ",(0,a.jsx)(n.code,{children:"foo"}),"\nexpects a regular function as an argument - those are incompatible."]}),"\n",(0,a.jsxs)(n.admonition,{type:"note",children:[(0,a.jsxs)(n.p,{children:["Variables contained within the ",(0,a.jsx)(n.code,{children:"||"})," are the closure's parameters, and the expression that follows it is the closure's body. The capture environment is comprised of any variables used in the closure's body that are not parameters."]}),(0,a.jsx)(n.p,{children:"E.g. in |x| x + y, y would be a captured variable, but x would not be, since it is a parameter of the closure."})]}),"\n",(0,a.jsxs)(n.p,{children:["The syntax for the type of a closure is ",(0,a.jsx)(n.code,{children:"fn[env](args) -> ret_type"}),", where ",(0,a.jsx)(n.code,{children:"env"})," is the capture environment of the closure -\nin this example that's ",(0,a.jsx)(n.code,{children:"(Field, Field)"}),"."]}),"\n",(0,a.jsxs)(n.p,{children:["The best solution in our case is to make ",(0,a.jsx)(n.code,{children:"foo"})," generic over the environment type of its parameter, so that it can be called\nwith closures with any environment, as well as with regular functions:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-rust",children:"fn foo<Env>(f: fn[Env]() -> Field) -> Field {\n f()\n}\n\nfn main() {\n  let (x, y) = (50, 50);\n  assert(foo(|| x + y) == 100); // compiles fine\n  assert(foo(|| 60) == 60);     // compiles fine\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(d,{...e})}):d(e)}},28453(e,n,s){s.d(n,{R:()=>t,x:()=>i});var o=s(96540);const a={},r=o.createContext(a);function t(e){const n=o.useContext(r);return o.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:t(e.components),o.createElement(r.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.