module ImmArr: { /* Put this in the interface file */ type t<'a> let make: array<'a> => t<'a> let isEmpty: t<'a> => bool let head: t<'a> => option<'a> let tail: t<'a> => t<'a> let toArray: t<'a> => array<'a> let map: (t<'a>, 'a => 'b) => t<'b> let cons: (t<'a>, 'a) => t<'a> let append: (t<'a>, 'a) => t<'a> } = { /* Put this in the module file */ type t<'a> = array<'a> let make = arr => arr->Js.Array2.sliceFrom(0) let isEmpty = t => t->Js.Array2.length === 0 let head = t => t->Belt.Array.get(0) let tail = t => isEmpty(t) ? [] : t->Js.Array2.sliceFrom(1) let toArray = make let map = Belt.Array.map let cons = (t, a) => [a]->Js.Array2.concat(t) let append = (t, a) => t->Js.Array2.concat([a]) } open ImmArr let originalData = [0, 1, 2] let immutable = make(originalData) Js.log2("head:", immutable->head) let dataTail = immutable->tail Js.log2("tail:", dataTail) Js.log2("cons:", immutable->cons(-1)) Js.log2("append:", immutable->append(3)) // ImmArr.t is an array, but can't be used as one, these are compile errors // dataTail->Js.Array2.push(3); // immutableArray->Js.Array2.push(3); // proof mutating the data you get doesn't modify the underlying structure originalData->Js.Array2.push(4)->ignore Js.log2("Has the immutable array changed?", immutable->toArray) immutable->toArray->Js.Array2.push(4)->ignore Js.log2("Has the immutable array changed?", immutable->toArray)