PageSourceSearch

https://rescript-idea.github.io/_next/static/chunks/pages/docs/manual/latest/function-9eb78baa8f48317387c5.js

js rescript-idea.github.io collected 2026-10-03 09:52:35 UTC 27,062 bytes, 1 lines download raw bytes

1(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[40611],{17375:function(e,n,t){"use strict";function a(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}t.d(n,{Z:function(){return a}})},60484:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return d}});var a=t(17375),r=t(96156),i=(t(67294),t(3905));function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function l(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){(0,r.Z)(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}var s,p=(s="CodeTab",function(e){return console.warn("Component "+s+" was not imported, exported, or provided by MDXProvider as global scope"),(0,i.kt)("div",l({},e))}),u={};function d(e){var n=e.components,t=(0,a.Z)(e,["components"]);return(0,i.kt)("wrapper",l(l(l({},u),t),{},{components:n,mdxType:"MDXLayout"}),(0,i.kt)("h1",l({},{id:"function"}),"Function"),(0,i.kt)("p",null,(0,i.kt)("em",{parentName:"p"},"Cheat sheet for the full function syntax at the end"),"."),(0,i.kt)("p",null,"ReScript functions are declared with an arrow and return an expression, just like JS functions. They compile to clean JS functions too."),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"C
1odeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res",metastring:"prelude",prelude:!0}),'let greet = (name) => "Hello " ++ name\n')),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),'function greet(name) {\n  return "Hello " + name;\n}\n'))),(0,i.kt)("p",null,"This declares a function and assigns to it the name ",(0,i.kt)("inlineCode",{parentName:"p"},"greet"),", which you can call like so:"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"CodeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res",metastring:"example",example:!0}),'greet("world!") // "Hello world!"\n')),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),'greet("world!");\n'))),(0,i.kt)("p",null,"Multi-arguments functions have arguments separated by comma:"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"CodeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res",metastring:"example",example:!0}),"let add = (x, y, z) => x + y + z\nadd(1, 2, 3) // 6\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"function add(x, y, z) {\n  return (x + y | 0) + z | 0;\n}\n"))),(0,i.kt)("p",null,"For longer functions, you'd surround the body with a block:"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"C
1odeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res",metastring:"example",example:!0}),'let greetMore = (name) => {\n  let part1 = "Hello"\n  part1 ++ " " ++ name\n}\n')),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),'function greetMore(name) {\n  return "Hello " + name;\n}\n'))),(0,i.kt)("p",null,"If your function has no argument, just write ",(0,i.kt)("inlineCode",{parentName:"p"},"let greetMore = () => {...}"),"."),(0,i.kt)("h2",l({},{id:"labeled-arguments"}),"Labeled Arguments"),(0,i.kt)("p",null,"Multi-arguments functions, especially those whose arguments are of the same type, can be confusing to call."),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"CodeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"let addCoordinates = (x, y) => {\n  // use x and y here\n}\n// ...\naddCoordinates(5, 6) // which is x, which is y?\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"function addCoordinates(x, y) {\n  // use x and y here\n}\n\naddCoordinates(5, 6);\n"))),(0,i.kt)("p",null,"You can attach labels to an argument by prefixing the name with the ",(0,i.kt)("inlineCode",{parentName:"p"},"~")," symbol:"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"C
1odeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"let addCoordinates = (~x, ~y) => {\n  // use x and y here\n}\n// ...\naddCoordinates(~x=5, ~y=6)\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"function addCoordinates(x, y) {\n  // use x and y here\n}\n\naddCoordinates(5, 6);\n"))),(0,i.kt)("p",null,"You can provide the arguments in ",(0,i.kt)("strong",{parentName:"p"},"any order"),":"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"CodeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"addCoordinates(~y=6, ~x=5)\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"addCoordinates(5, 6);\n"))),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"~x")," part in the declaration means the function accepts an argument labeled ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," and can refer to it in the function body by the same name. You can also refer to the arguments inside the function body by a different name for conciseness:"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"C
1odeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),'let drawCircle = (~radius as r, ~color as c) => {\n  setColor(c)\n  startAt(r, r)\n  // ...\n}\n\ndrawCircle(~radius=10, ~color="red")\n')),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),'function drawCircle(r, c) {\n  setColor(c);\n  return startAt(r, r);\n}\n\ndrawCircle(10, "red");\n'))),(0,i.kt)("p",null,"As a matter of fact, ",(0,i.kt)("inlineCode",{parentName:"p"},"(~radius)")," is just a shorthand for ",(0,i.kt)("inlineCode",{parentName:"p"},"(~radius as radius)"),"."),(0,i.kt)("p",null,"Here's the syntax for typing the arguments:"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"CodeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"let drawCircle = (~radius as r: int, ~color as c: string) => {\n  // code here\n}\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"function drawCircle(r, c) {\n  // code here\n}\n"))),(0,i.kt)("h2",l({},{id:"optional-labeled-arguments"}),"Optional Labeled Arguments"),(0,i.kt)("p",null,"Labeled function arguments can be made optional during declaration. You can then omit them when calling the function."),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"C
1odeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"// radius can be omitted\nlet drawCircle = (~color, ~radius=?, ()) => {\n  setColor(color)\n  switch radius {\n  | None => startAt(1, 1)\n  | Some(r_) => startAt(r_, r_)\n  }\n}\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),'var Caml_option = require("./stdlib/caml_option.js");\n\nfunction drawCircle(color, radius, param) {\n  setColor(color);\n  if (radius === undefined) {\n    return startAt(1, 1);\n  }\n  var r_ = Caml_option.valFromOption(radius);\n  return startAt(r_, r_);\n}\n'))),(0,i.kt)("p",null,"When given in this syntax, ",(0,i.kt)("inlineCode",{parentName:"p"},"radius")," is ",(0,i.kt)("strong",{parentName:"p"},"wrapped")," in the standard library's ",(0,i.kt)("inlineCode",{parentName:"p"},"option")," type, defaulting to ",(0,i.kt)("inlineCode",{parentName:"p"},"None"),". If provided, it'll be wrapped with a ",(0,i.kt)("inlineCode",{parentName:"p"},"Some"),". So ",(0,i.kt)("inlineCode",{parentName:"p"},"radius"),"'s type value is ",(0,i.kt)("inlineCode",{parentName:"p"},"None | Some(int)")," here."),(0,i.kt)("p",null,"More on ",(0,i.kt)("inlineCode",{parentName:"p"},"option")," type ",(0,i.kt)("a",l({parentName:"p"},{href:"null-undefined-option.md"}),"here"),"."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Note")," for the sake of the type system, whenever you have an optional argument, you need to ensure that there's also at least one positional argument (aka non-labeled, non-optional argument) after it. If there's none, provide a dummy ",(0,i.kt)("inlineCode",{parentName:"p"},"unit")," (aka ",(0,i.kt)("inlineCode",{parentName:"p"},"()"),") argument."),(0,i.kt)("h3",l({},{id:"signatures-and-type-annotations"}),"Signatures and Type Annotations"),(0,i.kt)("p",null,"Functions with optional labeled arguments can be confusing when it comes to signature and type annotations. Indeed, the type of an optional labeled argument looks different depending on whether you're calling the function, or working inside the function body. Outside the function, a raw value is either passed in (",(0,i.kt)("inlineCode",{parentName:"p"},"int"),", for example), or left off entirely. Inside the function, the parameter is always there, but its value is an option (",(0,i.kt)("inlineCode",{parentName:"p"},"option<int>"),"). This means that the type signature is different, depending on whether you're writing out the function type, or the parameter type annotation. The first being a raw value, and the second being an option."),(0,i.kt)("p",null,"If we get back to our previous example and both add a signature and type annotations to its argument, we get this:"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"C
1odeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"let drawCircle: (~color: color, ~radius: int=?, unit) => unit =\n  (~color: color, ~radius: option<int>=?, ()) => {\n    setColor(color)\n    switch radius {\n    | None => startAt(1, 1)\n    | Some(r_) => startAt(r_, r_)\n    }\n  }\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"function drawCircle(color, radius, param) {\n  setColor(color);\n  if (radius !== undefined) {\n    return startAt(radius, radius);\n  } else {\n    return startAt(1, 1);\n  }\n}\n"))),(0,i.kt)("p",null,"The first line is the function's signature, we would define it like that in an interface file (see ",(0,i.kt)("a",l({parentName:"p"},{href:"module.md#signatures"}),"Signatures"),"). The function's signature describes the types that the ",(0,i.kt)("strong",{parentName:"p"},"outside world")," interacts with, hence the type ",(0,i.kt)("inlineCode",{parentName:"p"},"int")," for ",(0,i.kt)("inlineCode",{parentName:"p"},"radius")," because it indeed expects an ",(0,i.kt)("inlineCode",{parentName:"p"},"int")," when called."),(0,i.kt)("p",null,"In the second line, we annotate the arguments to help us remember the types of the arguments when we use them ",(0,i.kt)("strong",{parentName:"p"},"inside")," the function's body, here indeed ",(0,i.kt)("inlineCode",{parentName:"p"},"radius")," will be an ",(0,i.kt)("inlineCode",{parentName:"p"},"option<int>")," inside the function."),(0,i.kt)("p",null,"So if you happen to struggle when writing the signature of a function with optional labeled arguments, try to remember this!"),(0,i.kt)("h3",l({},{id:"explicitly-passed-optional"}),"Explicitly Passed Optional"),(0,i.kt)("p",null,"Sometimes, you might want to forward a value to a function without knowing whether the value is ",(0,i.kt)("inlineCode",{parentName:"p"},"None")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"Some(a)"),". Naively, you'd do:"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"C
1odeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"let result =\n  switch payloadRadius {\n  | None => drawCircle(~color, ())\n  | Some(r) => drawCircle(~color, ~radius=r, ())\n  }\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"var r = payloadRadius;\n\nvar result = r !== undefined\n  ? drawCircle(color, Caml_option.valFromOption(r), undefined)\n  : drawCircle(color, undefined);\n"))),(0,i.kt)("p",null,"This quickly gets tedious. We provide a shortcut:"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"CodeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"let result = drawCircle(~color, ~radius=?payloadRadius, ())\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"var result = drawCircle(1, undefined, undefined);\n"))),(0,i.kt)("p",null,'This means "I understand ',(0,i.kt)("inlineCode",{parentName:"p"},"radius")," is optional, and that when I pass it a value it needs to be an ",(0,i.kt)("inlineCode",{parentName:"p"},"int"),", but I don't know whether the value I'm passing is ",(0,i.kt)("inlineCode",{parentName:"p"},"None")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"Some(val)"),", so I'll pass you the whole ",(0,i.kt)("inlineCode",{parentName:"p"},"option"),' wrapper".'),(0,i.kt)("h3",l({},{id:"optional-with-default-value"}),"Optional with Default Value"),(0,i.kt)("p",null,"Optional labeled arguments can also be provided a default value. In this case, they aren't wrapped in an ",(0,i.kt)("inlineCode",{parentName:"p"},"option")," type."),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"C
1odeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"let drawCircle = (~radius=1, ~color, ()) => {\n  setColor(color)\n  startAt(radius, radius)\n}\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"function drawCircle(radiusOpt, color, param) {\n  var radius = radiusOpt !== undefined ? radiusOpt : 1;\n  setColor(color);\n  return startAt(radius, radius);\n}\n"))),(0,i.kt)("h2",l({},{id:"recursive-functions"}),"Recursive Functions"),(0,i.kt)("p",null,"ReScript chooses the sane default of preventing a function to be called recursively within itself. To make a function recursive, add the ",(0,i.kt)("inlineCode",{parentName:"p"},"rec")," keyword after the ",(0,i.kt)("inlineCode",{parentName:"p"},"let"),":"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"CodeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res",metastring:"example",example:!0}),"let rec neverTerminate = () => neverTerminate()\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"function neverTerminate(_param) {\n  while(true) {\n    _param = undefined;\n    continue ;\n  };\n}\n"))),(0,i.kt)("p",null,"A simple recursive function may look like this:"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"C
1odeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res",metastring:"example",example:!0}),"// Recursively check every item on the list until one equals the `item`\n// argument. If a match is found, return `true`, otherwise return `false`\nlet rec listHas = (list, item) =>\n  switch list {\n  | list{} => false\n  | list{a, ...rest} => a === item || listHas(rest, item)\n  }\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"function listHas(_list, item) {\n  while(true) {\n    var list = _list;\n    if (!list) {\n      return false;\n    }\n    if (list.hd === item) {\n      return true;\n    }\n    _list = list.tl;\n    continue ;\n  };\n}\n"))),(0,i.kt)("p",null,"Recursively calling a function is bad for performance and the call stack. However, ReScript intelligently compiles ",(0,i.kt)("a",l({parentName:"p"},{href:"https://stackoverflow.com/questions/33923/what-is-tail-recursion"}),"tail recursion")," into a fast JavaScript loop. Try checking the JS output of the above code!"),(0,i.kt)("h3",l({},{id:"mutually-recursive-functions"}),"Mutually Recursive Functions"),(0,i.kt)("p",null,"Mutually recursive functions start like a single recursive function using the\n",(0,i.kt)("inlineCode",{parentName:"p"},"rec")," keyword, and then are chained together with ",(0,i.kt)("inlineCode",{parentName:"p"},"and"),":"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"C
1odeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res",metastring:"example",example:!0}),"let rec callSecond = () => callFirst()\nand callFirst = () => callSecond()\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"function callSecond(_param) {\n  while(true) {\n    _param = undefined;\n    continue ;\n  };\n}\n\nfunction callFirst(_param) {\n  while(true) {\n    _param = undefined;\n    continue ;\n  };\n}\n"))),(0,i.kt)("h2",l({},{id:"uncurried-function"}),"Uncurried Function"),(0,i.kt)("p",null,"ReScript's functions are curried by default, which is one of the few performance penalties we pay in the compiled JS output. The compiler does a best-effort job at removing those currying whenever possible. However, in certain edge cases, you might want guaranteed uncurrying. In those cases, put a dot in the function's parameter list:"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"CodeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res",metastring:"example",example:!0}),"let add = (. x, y) => x + y\n\nadd(. 1, 2)\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"function add(x, y) {\n  return x + y | 0;\n}\n\nadd(1, 2);\n"))),(0,i.kt)("p",null,"If you write down the uncurried function's type, you'll add a dot there as well."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Note"),": both the declaration site and the call site need to have the uncurry annotation. That's part of the guarantee/requirement."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"This feature seems trivial"),", but is actually one of our most important features, as a primarily functional language. We encourage you to use it if you'd like to remove any mention of ",(0,i.kt)("inlineCode",{parentName:"p"},"Curry")," runtime in the JS output."),(0,i.kt)("h2",l({},{id:"asyncawait-from-v101"}),"Async/Await (from v10.1)"),(0,i.kt)("p",null,"Just as in JS, an async function can be declared by adding ",(0,i.kt)("inlineCode",{parentName:"p"},"async")," before the definition, and ",(0,i.kt)("inlineCode",{parentName:"p"},"await")," can be used in the body of such functions.\nThe output looks like idiomatic JS:"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"C
1odeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res",metastring:"example",example:!0}),'let getUserName = async (userId) => userId\n\nlet greetUser = async (userId) => {\n  let name = await getUserName(userId)  \n  "Hello " ++ name ++ "!"\n}\n')),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),'async function greetUser(userId) {\n  var name = await getUserName(userId);\n  return "Hello " + name + "!";\n}\n'))),(0,i.kt)("p",null,"The return type of ",(0,i.kt)("inlineCode",{parentName:"p"},"getUser")," is inferred to be ",(0,i.kt)("inlineCode",{parentName:"p"},"promise<string>"),".\nSimilarly, ",(0,i.kt)("inlineCode",{parentName:"p"},"await getUserName(userId)")," returns a ",(0,i.kt)("inlineCode",{parentName:"p"},"string")," when the function returns ",(0,i.kt)("inlineCode",{parentName:"p"},"promise<string>"),".\nUsing ",(0,i.kt)("inlineCode",{parentName:"p"},"await")," outside of an ",(0,i.kt)("inlineCode",{parentName:"p"},"async")," function (including in a non-async callback to an async function) is an error."),(0,i.kt)("h3",l({},{id:"ergonomic-error-handling"}),"Ergonomic error handling"),(0,i.kt)("p",null,"Error handling is done by simply using ",(0,i.kt)("inlineCode",{parentName:"p"},"try"),"/",(0,i.kt)("inlineCode",{parentName:"p"},"catch"),", or a switch with an ",(0,i.kt)("inlineCode",{parentName:"p"},"exception")," case, just as in functions that are not async.\nBoth JS exceptions and exceptions defined in ReScript can be caught. The compiler takes care of packaging JS exceptions into the builtin ",(0,i.kt)("inlineCode",{parentName:"p"},"JsError")," exception:"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"C
1odeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res",metastring:"example",example:!0}),"exception SomeReScriptException\n\nlet somethingThatMightThrow = async () => raise(SomeReScriptException)\n\nlet someAsyncFn = async () => {\n  switch await somethingThatMightThrow() {\n  | data => Some(data)\n  | exception JsError(_) => None\n  | exception SomeReScriptException => None\n  }\n}\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),'var SomeReScriptException = /* @__PURE__ */Caml_exceptions.create("Example.SomeReScriptException");\n\nasync function someAsyncFn(param) {\n  var data;\n  try {\n    data = await somethingThatMightThrow(undefined);\n  }\n  catch (raw_exn){\n    var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);\n    if (exn.RE_EXN_ID === "JsError") {\n      return ;\n    }\n    if (exn.RE_EXN_ID === SomeReScriptException) {\n      return ;\n    }\n    throw exn;\n  }\n  return data;\n}\n'))),(0,i.kt)("h2",l({},{id:"the-ignore-function"}),"The ignore() Function"),(0,i.kt)("p",null,"Occasionally you may want to ignore the return value of a function. ReScript provides an ",(0,i.kt)("inlineCode",{parentName:"p"},"ignore()")," function that discards the value of its argument and returns ",(0,i.kt)("inlineCode",{parentName:"p"},"()"),":"),(0,i.kt)(p,{labels:["ReScript","JS Output"],mdxType:"C
1odeTab"},(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"mySideEffect()->Promise.catch(handleError)->ignore\n\nJs.Global.setTimeout(myFunc, 1000)->ignore\n")),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-js"}),"$$Promise.$$catch(mySideEffect(), function (prim) {\n  return handleError(prim);\n});\n\nsetTimeout(function (prim) {\n  myFunc();\n}, 1000);\n"))),(0,i.kt)("h2",l({},{id:"tips--tricks"}),"Tips & Tricks"),(0,i.kt)("p",null,"Cheat sheet for the function syntaxes:"),(0,i.kt)("h3",l({},{id:"declaration"}),"Declaration"),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"// anonymous function\n(x, y) => 1\n// bind to a name\nlet add = (x, y) => 1\n\n// labeled\nlet add = (~first as x, ~second as y) => x + y\n// with punning sugar\nlet add = (~first, ~second) => first + second\n\n// labeled with default value\nlet add = (~first as x=1, ~second as y=2) => x + y\n// with punning\nlet add = (~first=1, ~second=2) => first + second\n\n// optional\nlet add = (~first as x=?, ~second as y=?) => switch x {...}\n// with punning\nlet add = (~first=?, ~second=?) => switch first {...}\n")),(0,i.kt)("h4",l({},{id:"with-type-annotation"}),"With Type Annotation"),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"// anonymous function\n(x: int, y: int): int => 1\n// bind to a name\nlet add = (x: int, y: int): int => 1\n\n// labeled\nlet add = (~first as x: int, ~second as y: int) : int => x + y\n// with punning sugar\nlet add = (~first: int, ~second: int) : int => first + second\n\n// labeled with default value\nlet add = (~first as x: int=1, ~second as y: int=2) : int => x + y\n// with punning sugar\nlet add = (~first: int=1, ~second: int=2) : int => first + second\n\n// optional\nlet add = (~first as x: option<int>=?, ~second as y: option<int>=?) : int => switch x {...}\n// with punning sugar\n// note that the caller would pass an `int`, not `option<int>`\n// Inside the function, `first` and `second` are `option<int>`.\nlet add = (~first: option<int>=?, ~second: option<int>=?) : int => switch first {...}\n")),(0,i.kt)("h3",l({},{id:"application"}),"Application"),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"add(x, y)\n\n// labeled\nadd(~first=1, ~second=2)\n// with punning sugar\nadd(~first, ~second)\n\n// application with default value. Same as normal application\nadd(~first=1, ~second=2)\n\n// explicit optional application\nadd(~first=?Some(1), ~second=?Some(2))\n// with punning\nadd(~first?, ~second?)\n")),(0,i.kt)("h4",l({},{id:"with-type-annotation-1"}),"With Type Annotation"),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"// labeled\nadd(~first=1: int, ~second=2: int)\n// with punning sugar\nadd(~first: int, ~second: int)\n\n// application with default value. Same as normal application\nadd(~first=1: int, ~second=2: int)\n\n// explicit optional application\nadd(~first=?Some(1): option<int>, ~second=?Some(2): option<int>)\n// no punning sugar when you want to type annotate\n")),(0,i.kt)("h3",l({},{id:"standalone-type-signature"}),"Standalone Type Signature"),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res"}),"// first arg type, second arg type, return type\ntype add = (int, int) => int\n\n// labeled\ntype add = (~first: int, ~second: int) => int\n\n// labeled\ntype add = (~first: int=?, ~second: int=?, unit) => int\n")),(0,i.kt)("h4",l({},{id:"in-interface-files"}),"In Interface Files"),(0,i.kt)("p",null,"To annotate a function from the implementation file (",(0,i.kt)("inlineCode",{parentName:"p"},".res"),") in your interface file (",(0,i.kt)("inlineCode",{parentName:"p"},".resi"),"):"),(0,i.kt)("pre",null,(0,i.kt)("code",l({parentName:"pre"},{className:"language-res",metastring:"sig",sig:!0}),"let add: (int, int) => int\n")),(0,i.kt)("p",null,"The type annotation part is the same as the previous section on With Type Annotation."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Don't")," confuse ",(0,i.kt)("inlineCode",{parentName:"p"},"let add: myType")," with ",(0,i.kt)("inlineCode",{parentName:"p"},"type add = myType"),". When used in ",(0,i.kt)("inlineCode",{parentName:"p"},".resi")," interface files, the former exports the binding ",(0,i.kt)("inlineCode",{parentName:"p"},"add")," while annotating it as type ",(0,i.kt)("inlineCode",{parentName:"p"},"myType"),". The latter exports the type ",(0,i.kt)("inlineCode",{parentName:"p"},"add"),", whose value is the type ",(0,i.kt)("inlineCode",{parentName:"p"},"myType"),"."))}d.isMDXComponent=!0,d.frontmatter={title:"Function",description:"Function syntax in ReScript",canonical:"/docs/manual/latest/function",__ghEditHref:"https://github.com/reason-association/rescript-lang.org/blob/master/pages/docs/manual/latest/function.mdx"}},9630:function(e,n,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/docs/manual/latest/function",function(){return t(60484)}])}},function(e){e.O(0,[92888,49774,40179],(function(){return n=9630,e(e.s=n);var n}));var n=e.O();_N_E=n}]);

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.