{"componentChunkName":"component---src-lekoarts-gatsby-theme-minimal-blog-core-templates-post-query-tsx","path":"/fold-right-and-fold-left","result":{"data":{"post":{"slug":"/fold-right-and-fold-left","title":"fold_right and fold_left","date":"January 17, 2019","tags":[{"name":"Functional Programming","slug":"functional-programming"}],"description":null,"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"fold_right and fold_left\",\n  \"date\": \"2019-01-17T00:00:00.000Z\",\n  \"tags\": [\"Functional Programming\"],\n  \"excerpt\": \"fold in OCaml\"\n};\n\nvar makeShortcode = function makeShortcode(name) {\n  return function MDXDefaultShortcode(props) {\n    console.warn(\"Component \" + name + \" was not imported, exported, or provided by MDXProvider as global scope\");\n    return mdx(\"div\", props);\n  };\n};\n\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"credits: textbook from Cornell\\u2019s \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://www.cs.cornell.edu/courses/cs3110/2019sp/textbook/hop/fold_left.html\"\n  }), \"cs 3110\"), \".\"), mdx(\"p\", null, \"Some useful explanations for \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"fold\"), \" functions in OCaml.\"), mdx(\"hr\", null), mdx(\"h4\", null, \"fold_right\"), mdx(\"p\", null, \"Let\\u2019s start with two functions: \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"sum\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"concat\")), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-ocaml\"\n  }), \"let rec sum = function\\n| [] -> 0\\n| h::t -> h + sum t\\n\\nlet rec concat = function\\n| [] -> \\\"\\\"\\n| h::t -> h ^ concat t\\n\")), mdx(\"p\", null, \"We notice that these two functions are very similar. The only differences are the base case value (\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"0\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"\\\"\\\"\"), \") and the operator (\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"+\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"^\"), \").\"), mdx(\"p\", null, \"We love excerptions. So we rewrite these two functions as\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-ocaml\"\n  }), \"let rec combine op init = function\\n| [] -> init\\n| h::t -> op h (combine op init t)\\n\")), mdx(\"p\", null, \"Why is it called fold_right?\"), mdx(\"p\", null, \"Because the associativity is from right to left like this:\"), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"(a+(b+(c+0)))\")), mdx(\"h4\", null, \"fold_left\"), mdx(\"p\", null, \"Similarly, the associativity, as its name suggests, is \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"((a+0)+b)+c)\"), \". It is actually a handy function for tail recursion.\"), mdx(\"p\", null, \"It is implemented like this:\"), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"fold_left op acc(base case) list\")), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, \"In \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"fold_right\"), \", you will notice that the value passed as the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"init\"), \"argument is the same for every recursive invocation of \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"fold_right\"), \": it\\u2019s passed all the way down to where it\\u2019s needed, at the right-most element of the list, then used there exactly once. But in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"fold_left\"), \", you will notice that at each recursive invocation, the value passed as the argument \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"acc\"), \" can be different.\")), mdx(\"p\", null, \"NOTE: In \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"fold_left\"), \", its type is:\"), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun>\"), \"\\nIn the example \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"rev\"), \" below, the function is \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"fun l a\"), \" instead of \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"fun a l\")), mdx(\"h4\", null, \"Examples\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-ocaml\"\n  }), \"(* reverse a list *)\\nlet rev lst = fold_left (fun l a -> a::l) [] lst\\n\\n(* calculate the length of a list*)\\nlet len lst = fold_left (fun a _ -> a+1) 0 lst\\n\\n(* map in fold*)\\nlet mapp f lst = fold_right (fun e_of_l init -> (f e_of_l)::init) lst [] ;;\\n\\n(* filter in fold*)\\nlet filterr f lst = fold_right (fun e_of_l init -> if (f e_of_l) then e_of_l::init else init) lst [] ;;\\n\\n\")));\n}\n;\nMDXContent.isMDXComponent = true;","excerpt":"fold in OCaml","banner":null}},"pageContext":{"slug":"/fold-right-and-fold-left"}}}