{"id":15757906,"url":"https://github.com/12joan/rubio","last_synced_at":"2026-01-28T17:33:45.618Z","repository":{"id":103339387,"uuid":"268523332","full_name":"12joan/rubio","owner":"12joan","description":"Write pure, functional code that encapsulates side effects using the IO monad (and friends) in Ruby","archived":false,"fork":false,"pushed_at":"2021-06-10T18:00:01.000Z","size":166,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-30T21:11:15.600Z","etag":null,"topics":["functional-programming","io-monad","maybe-monad","state-monad"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/12joan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-06-01T13:01:31.000Z","updated_at":"2021-06-10T18:00:04.000Z","dependencies_parsed_at":"2023-07-07T18:03:38.335Z","dependency_job_id":null,"html_url":"https://github.com/12joan/rubio","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/12joan/rubio","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/12joan%2Frubio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/12joan%2Frubio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/12joan%2Frubio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/12joan%2Frubio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/12joan","download_url":"https://codeload.github.com/12joan/rubio/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/12joan%2Frubio/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28847833,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T15:15:36.453Z","status":"ssl_error","status_checked_at":"2026-01-28T15:15:13.020Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["functional-programming","io-monad","maybe-monad","state-monad"],"created_at":"2024-10-04T09:40:47.677Z","updated_at":"2026-01-28T17:33:45.603Z","avatar_url":"https://github.com/12joan.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rubio\n\n![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/12joan/rubio?color=g\u0026label=version) [![Build Status](https://travis-ci.com/12joan/rubio.svg?branch=master)](https://travis-ci.com/12joan/rubio) [![Maintainability](https://api.codeclimate.com/v1/badges/e435a25bf4b6197b464e/maintainability)](https://codeclimate.com/github/12joan/rubio/maintainability) [![Coverage Status](https://coveralls.io/repos/github/12joan/rubio/badge.svg?branch=master)](https://coveralls.io/github/12joan/rubio?branch=master)\n\nWrite pure, functional code that encapsulates side effects using the IO monad (and friends) in Ruby.\n\n## Contents\n\n- [1. Installation](#1-installation)\n- [2. Usage and syntax](#2-usage-and-syntax)\n  - [2.1 `main :: IO`](#21-main--io)\n  - [2.2 `\u003e\u003e` operator for monads](#22--operator-for-monads)\n  - [2.3 Function composition](#23-function-composition)\n  - [2.4 Partially applying functions in Ruby](#24-partially-applying-functions-in-ruby)\n  - [2.5 `%` operator](#25--operator)\n  - [2.6 Expose/extend pattern](#26-exposeextend-pattern)\n- [3. Built-in modules](#3-built-in-modules)\n  - [3.1 `Rubio::IO::Core`](#31-rubioiocore)\n    - [3.1.1 Limitations](#311-limitations)\n    - [3.1.2 Built-in functions](#312-built-in-functions)\n  - [3.2 `Rubio::Maybe::Core`](#32-rubiomaybecore)\n    - [3.2.1 Unwraping `Maybe a -\u003e a`](#321-unwraping-maybe-a---a)\n      - [3.2.1.1 Ruby \u003c 2.7](#3211-ruby--27)\n      - [3.2.1.2 Ruby \u003e= 2.7](#3212-ruby--27)\n    - [3.2.2 Built-in functions](#322-built-in-functions)\n    - [3.2.3 Converting nillable results to `Maybe`](#323-converting-nillable-results-to-maybe) \n  - [3.3 `Rubio::State::Core`](#33-rubiostatecore)\n    - [3.3.1 Built-in functions](#331-built-in-functions)\n      - [3.3.1.1 `State`](#3311-state)\n      - [3.3.1.2 `StateIO`](#3312-stateio)\n  - [3.4 `Rubio::Unit::Core`](#34-rubiounitcore)\n    - [3.4.1 Built-in functions](#341-built-in-functions)\n  - [3.5 `Rubio::Functor::Core`](#35-rubiofunctorcore)\n    - [3.5.1 Built-in functions](#351-built-in-functions)\n  - [3.6 `Rubio::Expose`](#36-rubioexpose)\n- [4. Examples](#4-examples)\n\n## 1. Installation\n\nAdd the following line to your Gemfile.\n\n```ruby\ngem \"rubio\", github: \"12joan/rubio\"\n```\n\n## 2. Usage and syntax\n\n### 2.1 `main :: IO`\n\nAll programs written using Rubio are encouraged to construct and then invoke a `main` value which describes the entire behaviour of the program. `IO#perform!` is the equivalent of [`unsafePerformIO`](https://hackage.haskell.org/package/base-4.9.0.0/docs/System-IO-Unsafe.html#v:unsafePerformIO)  in Haskell, and must be explicitly called at the bottom of the program in order for the program to run. \n\n```ruby\nrequire \"rubio\"\n\ninclude Rubio::IO::Core\n\n# agree :: String -\u003e String\nagree = -\u003e(favourite) {\n  \"I like the #{favourite.chomp} monad too! 🙂\"\n}\n\n# main :: IO\nmain = println[\"What's your favourite monad?\"] \u003e\u003e getln \u003e\u003e (println \u003c\u003c agree)\nmain.perform!\n```\n\n`Rubio::IO::Core` provides a number of standard IO operations, such as `println` and `getln`. \n\n### 2.2 `\u003e\u003e` operator for monads\n\nMonads are \"composed\" using the `\u003e\u003e` (bind) operator. Note that unlike in Haskell,  `\u003e\u003e`  behaves differently depending on whether the right operand is a function or a monad. \n\n```haskell\n-- When the right operand is a function (equivalent to (\u003e\u003e=) in Haskell)\n(\u003e\u003e) :: Monad m =\u003e m a -\u003e (a -\u003e m b) -\u003e m b\n\n-- When the right operand is a monad (equivalent to (\u003e\u003e) in Haskell)\n(\u003e\u003e) :: Monad m =\u003e m a -\u003e m b -\u003e m b\n```\n\nFor example:\n\n- `println[\"hello\"] \u003e\u003e println[\"world\"]` returns a single `IO` which, when performed, will output \"hello\" and then \"world\". \n- `getln \u003e\u003e println` returns an IO which prompts for user input (as per `Kernel#gets`) and passes the result to `println`.\n- `getln \u003e\u003e -\u003e(x) { println[x] }` is equivalent to `getln \u003e\u003e println`.\n\nNote that whereas `getln` is a value of type `IO`, `println` is a function of type `String -\u003e IO`. \n\n### 2.3 Function composition\n\nRuby Procs can be composed using the built-in `\u003e\u003e` and `\u003c\u003c` operators. \n\n```ruby\nadd10 = -\u003e(x) { x + 10 }\ndouble = -\u003e(x) { x * 2 }\n\nadd10_and_double = double \u003c\u003c add10\ndouble_and_add10 = double \u003e\u003e add10\n\nadd10_and_double[5] #=\u003e 30\ndouble_and_add10[5] #=\u003e 20\n```\n\n### 2.4 Partially applying functions in Ruby\n\nRuby `Proc`s are not curried by default. In order to partially apply a function, you must first call `Proc#curry` on it. \n\n```ruby\nadd = -\u003e(x, y) {\n  x + y\n}.curry\n\nadd[6, 4] #=\u003e 10\nadd[6][4] #=\u003e 10\n\nadd10 = add[10] \n\nadd10[5] #=\u003e 15\n```\n\n### 2.5 `%` operator\n\nRubio monkey patches the `%` operator, which is an alias for `fmap`, onto `Proc` and `Method`. \n\n```ruby\ninclude Rubio::Maybe::Core\n\nreverse = proc(\u0026:reverse)\n\nreverse % Just[\"Hello\"] #=\u003e Just \"olleH\"\nreverse % Nothing #=\u003e Nothing\n```\n\n### 2.6 Expose/extend pattern\n\nFor a function or value defined in a module to be \"includable\" (either with `include` or `extend`), it must be wrapped inside a method. \n\n```ruby\nmodule SomeStandardFunctions\n  # not includable\n  add = -\u003e(x, y) { x + y }\n  \n  # includable\n  def multiply\n    -\u003e(x, y) { x * y }\n  end\nend\n\nmodule SomewhereElse\n  extend SomeStandardFunctions\n  \n  add[4, 6] #=\u003e NameError (undefined local variable or method `add' for SomewhereElse:Module)\n  \n  multiply[4, 6] #=\u003e 24\nend\n```\n\nTo make the syntax for this nicer, Rubio provides the `Rubio::Expose` module. \n\n```ruby\nmodule SomeStandardFunctions\n  extend Rubio::Expose\n  \n  expose :add,      -\u003e(x, y) { x + y }\n  expose :multiply, -\u003e(x, y) { x * y }\nend\n\nmodule SomewhereElse\n  extend SomeStandardFunctions\n  \n  add[4, 6] #=\u003e 10\n  multiply[4, 6] #=\u003e 24\nend\n```\n\n## 3. Built-in modules\n\n### 3.1 `Rubio::IO::Core`\n\n#### 3.1.1 Limitations\n\nCurrently, the `Rubio::IO::Core` module provides a limited subset of the functionality available via calling methods on `Kernel`. Custom `IO` operations can be defined as follows. \n\n```ruby\n# runCommand :: String -\u003e IO String\nrunCommand = -\u003e(cmd) {\n  Rubio::IO.new { `#{cmd}` }\n}\n```\n\n#### 3.1.2 Built-in functions\n\n- `pureIO :: a -\u003e IO a`\n  \n  Wraps a value in the `IO` monad.\n  \n  ```ruby\n  include Rubio::IO::Core\n  \n  # io :: IO Integer\n  io = pureIO[5]\n  io.perform! #=\u003e 5\n  ```\n  \n  Useful for adhering to the contract of the bind operator. In the example below, the anonymous function defined on `input` takes a `String` and returns an `IO String`. \n  \n  ```ruby\n  include Rubio::IO::Core\n  \n  main = getln \u003e\u003e -\u003e(input) { pureIO[input.reverse] } \u003e\u003e println\n  main.perform!\n  ```\n  \n- `println :: String -\u003e IO`\n\n  Encapsulates `Kernel#puts`. \n\n  ```ruby\n  include Rubio::IO::Core\n  \n  main = println[\"Hello world!\"]\n  main.perform!\n  ```\n\n  ```ruby\n  include Rubio::IO::Core\n  \n  main = pureIO[\"This works too!\"] \u003e\u003e println\n  main.perform!\n  ```\n\n- `getln :: IO`\n\n  Encapsulates `Kernel#gets`.\n\n  ```ruby\n  include Rubio::IO::Core\n  \n  doSomethingWithUserInput = -\u003e(input) {\n    println[\"You just said: #{input}\"]\n  }\n  \n  main = getln \u003e\u003e doSomethingWithUserInput\n  main.perform!\n  ```\n\n- `openFile :: String -\u003e String -\u003e IO File`\n\n  Encapsulates `Kernel#open`. First argument is the path to the file; second argument is the mode.\n\n  ```ruby\n  include Rubio::IO::Core\n  \n  # io :: IO File\n  io = openFile[\"README.md\", \"r\"]\n  io.perform! #=\u003e #\u003cFile:README.md\u003e\n  ```\n\n  ```ruby\n  require \"open-uri\"\n  \n  include Rubio::IO::Core\n  \n  main = openFile[\"https://ifconfig.me\"][\"r\"] \u003e\u003e -\u003e(handle) {\n    readFile[handle] \u003e\u003e println \u003e\u003e hClose[handle]\n  }\n  \n  main.perform! #=\u003e \"216.58.204.5\"\n  ```\n\n- `hClose :: File -\u003e IO`\n\n  Encapsulates `File#close`. Note that `withFile` is generally preferred.\n\n- `readFile :: File -\u003e IO String`\n\n  Encapsulates `File#read`.\n\n  ```ruby\n  include Rubio::IO::Core\n  \n  # ...\n  # someFile :: IO File\n  \n  main = someFile \u003e\u003e readFile \u003e\u003e println\n  main.perform! #=\u003e \"Contents of someFile\"\n  ```\n\n- `bracket :: IO a -\u003e (a -\u003e IO b) -\u003e (a -\u003e IO c) -\u003e IO c`\n\n  Pattern to automatically acquire a resource, perform a computation, and then release the resource. \n\n  The first argument is performed to acquire the resource of type `a`. The resource is then passed to the third argument. This returns an `IO c`, which will eventually be returned by `bracket`. Finally, the second argument is called to release the resource. \n\n  This pattern is used by `withFile` to automatically close the file handle. \n\n  ```ruby\n  include Rubio::IO::Core\n  \n  # withFile :: String -\u003e String -\u003e (File -\u003e IO a) -\u003e IO a\n  withFile = -\u003e(path, mode) {\n    bracket[ openFile[path, mode] ][ hClose ]\n  }.curry\n  \n  withFile[\"README.md\", \"r\"][readFile] #=\u003e IO String\n  ```\n\n- `withFile :: String -\u003e String -\u003e (File -\u003e IO a) -\u003e IO a`\n\n  Acquires a file handle, performs a computation, and then closes the file handle.\n\n  ```ruby\n  require \"open-uri\"\n  \n  include Rubio::IO::Core\n  \n  main = withFile[\"https://ifconfig.me\"][\"r\"][readFile] \u003e\u003e println\n  main.perform! #=\u003e \"216.58.204.5\"\n  ```\n\n### 3.2 `Rubio::Maybe::Core`\n\n#### 3.2.1 Unwraping `Maybe a -\u003e a`\n\n##### 3.2.1.1 Ruby \u003c 2.7\n\n`Maybe#get!` will return `x` in the case of `Just[x]`, or `nil` in the case of `Nothing`. \n\nIf you call `get!`, you should explicitly handle the case where `get!` returns `nil`. \n\n```ruby\ninclude Rubio::Maybe::Core\n\ndoSomethingWithMaybe = -\u003e(maybe) {\n  case\n  when x = maybe.get!\n    \"You got #{x}!\"\n  else\n    \"You got nothing.\"\n  end\n}\n\ndoSomethingWithMaybe[ Just[\"pattern matching\"] ] #=\u003e \"You got pattern matching!\"\ndoSomethingWithMaybe[ Nothing ] #=\u003e \"You got nothing.\"\n```\n\nNote that if `x` is a \"falsey\" value, such as `false` or `nil`, you must explicitly check for `Rubio::Maybe::JustClass` or `Rubio::Maybe::NothingClass`. \n\n```ruby\ninclude Rubio::Maybe::Core\n\ndoSomethingWithMaybe = -\u003e(maybe) {\n  case maybe\n  when Rubio::Maybe::JustClass\n    \"You got #{maybe.get!}!\"\n  when Rubio::Maybe::NothingClass\n    \"You got nothing.\"\n  end\n}\n\ndoSomethingWithMaybe[ Just[false] ] #=\u003e \"You got false!\"\ndoSomethingWithMaybe[ Nothing ] #=\u003e \"You got nothing.\"\n```\n\nAlternatively, `Maybe#get_or_else(y)` will return `x` in the case of `Just[x]`, or `y` in the case of `Nothing`.\n\n```ruby\ninclude Rubio::Maybe::Core\n\norEmptyString = -\u003e(maybe) {\n  maybe.get_or_else(\"\")\n}\n\norEmptyString[ Just[\"hello\"] ] #=\u003e \"hello\"\norEmptyString[ Nothing ] #=\u003e \"\"\n```\n\n##### 3.2.1.2 Ruby \u003e= 2.7\n\nRuby 2.7 introduces support for pattern matching, which allows for much nicer syntax when working with `Maybe`. \n\n```ruby\ninclude Rubio::Maybe::Core\n\ndoSomethingWithMaybe = -\u003e(maybe) {\n  case maybe\n  in Just[x]\n    \"You got #{x}!\"\n  in Nothing\n    \"You got nothing.\"\n  end\n}\n\ndoSomethingWithMaybe[ Just[\"even better pattern matching\"] ] #=\u003e \"You got even better pattern matching!\"\ndoSomethingWithMaybe[ Nothing ] #=\u003e \"You got nothing.\"\n```\n\n#### 3.2.2 Built-in functions\n\n- `Just :: a -\u003e Maybe a`\n\n  Constructs a `Just` value for the given argument. \n\n  ```ruby\n  include Rubio::Maybe::Core\n  \n  maybe = Just[5]\n  maybe.inspect #=\u003e \"Just 5\"\n  ```\n\n- `Nothing :: Maybe`\n\n  Singleton `Nothing` value. \n\n  ```ruby\n  include Rubio::Maybe::Core\n  \n  divide = -\u003e(x, y) {\n    if y == 0\n      Nothing\n    else\n      Just[x / y]\n    end\n  }.curry\n  \n  divide[12, 2] #=\u003e Just 6\n  divide[12, 0] #=\u003e Nothing\n  \n  double = -\u003e(x) { x * 2 }\n  \n  double % divide[12, 2] #=\u003e Just 12\n  double % divide[12, 0] #=\u003e Nothing\n  ```\n\n- `pureMaybe :: a -\u003e Maybe a`\n\n  Alias for `Just`.\n\n  ```ruby\n  include Rubio::Maybe::Core\n  \n  maybe1 = Just[5]\n  maybe1.inspect #=\u003e \"Just 5\"\n  \n  maybe2 = pureMaybe[5]\n  maybe2.inspect #=\u003e \"Just 5\"\n  ```\n\n#### 3.2.3 Converting nillable results to `Maybe`\n\nRubio defines `to_maybe` on `Object` and `NilClass`. \n\n```ruby\nhash = { a: 1, b: 2, c: 3 }\n\nmaybe1 = hash[:a].to_maybe\nmaybe1.inspect #=\u003e \"Just 1\"\n\nmaybe2 = hash[:e].to_maybe\nmaybe2.inspect #=\u003e \"Nothing\"\n```\n\n### 3.3 `Rubio::State::Core`\n\n#### 3.3.1 Built-in functions\n\n##### 3.3.1.1 `State`\n\n- `State :: (s -\u003e (a, s)) -\u003e State s a`\n\n  Constructs a `State` object with the given function. Note that since Ruby does not support tuples, you are expected to use an `Array` as the return value of the function. \n\n  ```ruby\n  include Rubio::State::Core\n  include Rubio::Unit::Core\n  \n  # push :: a -\u003e State [a] ()\n  push = -\u003e(x) { State[\n    -\u003e(xs) { [unit, [x] + xs] }\n  ]}\n  \n  # pop :: State [a] a\n  pop = State[\n    -\u003e(xs) { [ xs.first, xs.drop(1) ] }\n  ]\n  \n  # pop :: State [a] a\n  complexOperation = push[1] \u003e\u003e push[2] \u003e\u003e push[3] \u003e\u003e pop\n  \n  runState[ complexOperation ][ [10, 11] ] #=\u003e [3, [2, 1, 10, 11]]\n  ```\n\n  Often, composing `State` objects using the functions listed below is preferable to calling the `State` constructor directly.\n  \n- `pureState :: a -\u003e State s a`\n\n  Constructs a `State` object which sets the result and leaves the state unchanged.\n\n  ```ruby\n  include Rubio::State::Core\n  \n  # operation :: State s Integer\n  operation = pureState[123]\n  runState[ operation ][ \"initial state\" ] #=\u003e [123, \"initial state\"]\n  ```\n\n- `get :: State s s`\n\n  A `State` object that sets the result equal to the state.\n\n  ```ruby\n  include Rubio::State::Core\n  \n  # operation1 :: State s Integer\n  operation1 = pureState[123]\n  runState[ operation1 ][ \"initial state\" ] #=\u003e [123, \"initial state\"]\n  \n  # operation2 :: State s s\n  operation2 = pureState[123] \u003e\u003e get\n  runState[ operation2 ][ \"initial state\" ] #=\u003e [\"initial state\", \"initial state\"]\n  ```\n\n  Often used to retrieve the current state just before `\u003e\u003e`. \n\n  ```ruby\n  include Rubio::State::Core\n  \n  # operation :: State [a] [a]\n  operation = get \u003e\u003e -\u003e(state) {\n    pureState[state.reverse]\n  }\n  \n  runState[ operation ][ \"initial state\" ] #=\u003e [\"etats laitini\", \"initial state\"]\n  ```\n\n- `put :: s -\u003e State s ()`\n\n  Constructs a `State` object which sets the state.\n\n  ```ruby\n  include Rubio::State::Core\n  \n  # operation :: State String ()\n  operation = put[\"new state\"]\n  runState[ operation ][ \"initial state\" ] #=\u003e [(), \"new state\"]\n  ```\n\n- `modify :: (s -\u003e s) -\u003e State s ()`\n\n  Constructs a `State` object which applies the function to the state.\n\n  ```ruby\n  include Rubio::State::Core\n  \n  # reverse :: [a] -\u003e [a]\n  reverse = proc(\u0026:reverse)\n  \n  # operation :: State [a] ()\n  operation = modify[reverse]\n  runState[ operation ][ \"initial state\" ] #=\u003e [(), \"etats laitini\"]\n  ```\n\n- `gets :: (s -\u003e a) -\u003e State s a`\n\n  Constructs a `State` object that sets the result equal to `f[s]`, where `f` is the given function and `s` is the state.\n\n  ```ruby\n  include Rubio::State::Core\n  \n  # count :: [a] -\u003e Integer\n  count = proc(\u0026:count)\n  \n  # operation :: State [a] Integer\n  operation = gets[count]\n  runState[ operation ][ [1, 2, 3, 4, 5] ] #=\u003e [5, [1, 2, 3, 4, 5]]\n  ```\n\n- `runState :: State s a -\u003e s -\u003e (a, s)`\n\n  Runs a `State` object against an initial state. Returns a tuple containing the final result and the final state. \n\n  ```ruby\n  include Rubio::State::Core\n  \n  # push :: a -\u003e State [a] ()\n  push = -\u003e(x) {\n    modify[ -\u003e(xs) {\n      [x] + xs\n    }]\n  }\n  \n  head = proc(\u0026:first)\n  tail = -\u003e(xs) { xs.drop(1) }\n  \n  # pop :: State [a] a\n  pop = gets[head] \u003e\u003e -\u003e(x) {\n    modify[tail] \u003e\u003e pureState[x]\n  }\n  \n  # operation :: State [a] ()\n  operation = pop \u003e\u003e -\u003e(a) {\n    pop \u003e\u003e -\u003e(b) {\n      push[a] \u003e\u003e push[b]\n    }\n  }\n  \n  runState[ operation ][ [1, 2, 3, 4] ] #=\u003e [(), [2, 1, 3, 4]]\n  ```\n\n- `evalState :: State s a -\u003e s -\u003e a`\n\n  As per `runState`, except it only returns the final result. \n\n  ```ruby\n  include Rubio::State::Core\n  \n  # operation :: State String String\n  operation = put[\"final state\"] \u003e\u003e pureState[\"final result\"]\n  evalState[ operation ][ \"initial state\" ] #=\u003e \"final result\"\n  ```\n\n- `execState :: State s a -\u003e s -\u003e s`\n\n  As per `runState`, except it only returns the final state. \n\n  ```ruby\n  include Rubio::State::Core\n  \n  # operation :: State String String\n  operation = put[\"final state\"] \u003e\u003e pureState[\"final result\"]\n  execState[ operation ][ \"initial state\" ] #=\u003e \"final state\"\n  ```\n  \n##### 3.3.1.2 `StateIO`\n\n- `StateIO :: (s -\u003e IO (a, s)) -\u003e StateIO s IO a`\n\n  `IO` variety of `State`.\n\n  ```ruby\n  include Rubio::State::Core\n  include Rubio::IO::Core\n  \n  operation = StateIO[\n    -\u003e(s) {\n      println[\"The current state is #{s.inspect}\"] \u003e\u003e pureIO[ [\"result\", s.reverse] ]\n    }\n  ]\n  \n  io = runStateT[operation][ [1, 2, 3] ] #=\u003e IO\n  io.perform!\n  # The current state is [1, 2, 3]\n  #=\u003e [\"result\", [3, 2, 1]] \n  ```\n  \n- `liftIO :: IO a -\u003e StateIO s IO a`\n\n  Lift an `IO` into the `StateIO` monad. Useful for performing `IO` operations during a computation.\n\n  ```ruby\n  include Rubio::State::Core\n  include Rubio::IO::Core\n  \n  operation = (liftIO \u003c\u003c println)[\"Hello world!\"]\n  \n  io = execStateT[operation][ [1, 2, 3] ] #=\u003e IO\n  io.perform!\n  # Hello world!\n  #=\u003e [3, 2, 1]\n  ```\n\n- `pureStateIO :: a -\u003e StateIO s IO a`\n\n  `IO` variety of `pureState`.\n\n- `getIO :: StateIO s IO s`\n\n  `IO` variety of `get`.\n\n- `putIO :: s -\u003e StateIO s IO ()`\n\n  `IO` variety of `put`.\n\n- `modifyIO :: (s -\u003e s) -\u003e StateIO s IO ()`\n\n  `IO` variety of `modify.`\n  \n- `getsIO :: (s -\u003e a) -\u003e StateIO s a`\n\n  `IO` variety of `gets`.\n  \n- `runStateT -\u003e StateIO s IO a -\u003e s -\u003e IO (a, s)`\n\n  `IO` variety of `runState`.\n\n  ```ruby\n  include Rubio::State::Core\n  include Rubio::IO::Core\n  \n  operation = putIO[\"final state\"] \u003e\u003e pureStateIO[\"final result\"]\n  \n  io = runStateT[ operation ][ \"initial state\" ] #=\u003e IO\n  io.perform! #=\u003e [\"final result\", \"final state\"]\n  ```\n\n- `evalStateT :: StateIO s IO a -\u003e s -\u003e IO a`\n\n  `IO` variety of `evalState`.\n  \n  ```ruby\n  include Rubio::State::Core\n  include Rubio::IO::Core\n  \n  operation = putIO[\"final state\"] \u003e\u003e pureStateIO[\"final result\"]\n  \n  io = evalStateT[ operation ][ \"initial state\" ] #=\u003e IO\n  io.perform! #=\u003e \"final result\"\n  ```\n\n- `execStateT :: StateIO s IO a -\u003e s -\u003e IO s`\n\n  `IO` variety of `execState`.\n\n  ```ruby\n  include Rubio::State::Core\n  include Rubio::IO::Core\n  \n  operation = putIO[\"final state\"] \u003e\u003e pureStateIO[\"final result\"]\n  \n  io = execStateT[ operation ][ \"initial state\" ] #=\u003e IO\n  io.perform! #=\u003e \"final state\"\n  ```\n\n### 3.4 `Rubio::Unit::Core`\n\n#### 3.4.1 Built-in functions\n\n- `unit :: ()`\n\n  Singleton `()` value.\n\n  ```ruby\n  include Rubio::Unit::Core\n  \n  unit.inspect #=\u003e \"()\"\n  ```\n\n### 3.5 `Rubio::Functor::Core`\n\n#### 3.5.1 Built-in functions\n\n- `fmap :: Functor f =\u003e (a -\u003e b) -\u003e f a -\u003e f b`\n\n  Calls `fmap` on the second argument with the given function.\n\n  ```ruby\n  include Rubio::Functor::Core\n  include Rubio::IO::Core\n  \n  io1 = pureIO[\"Hello\"]\n  \n  reverse = proc(\u0026:reverse)\n  \n  io2 = fmap[reverse][io1]\n  io2.perform! #=\u003e \"olleH\"\n  ```\n  \n  ```ruby\n  include Rubio::Functor::Core\n  include Rubio::Maybe::Core\n  \n  reverse = proc(\u0026:reverse)\n  \n  fmap[reverse][ Just[\"Hello\"] ] #=\u003e Just \"olleH\"\n  fmap[reverse][ Nothing ] #=\u003e Nothing\n  ```\n  \n  ```ruby\n  include Rubio::Functor::Core\n  \n  CustomType = Struct.new(:value) do\n    def fmap(f)\n      self.class.new( f[value] )\n    end\n  end\n  \n  obj = CustomType.new(\"Hello\")\n  \n  reverse = proc(\u0026:reverse)\n  \n  fmap[reverse][obj] #=\u003e #\u003cstruct CustomType value=\"olleH\"\u003e\n  ```\n  \n  Note that the infix `%` operator can also be used without including `Rubio::Functor::Core`. \n  \n  ```ruby\n  include Rubio::Maybe::Core\n  \n  reverse = proc(\u0026:reverse)\n  \n  reverse % Just[\"Hello\"] #=\u003e Just \"olleH\"\n  reverse % Nothing #=\u003e Nothing\n  ```\n  \n### 3.6 `Rubio::Expose`\n\n#### 3.6.1 Methods\n\n- `expose(method_name, value) -\u003e value`\n\n  Defines a getter method for the given value.\n\n  ```ruby\n  module StdMath\n    extend Rubio::Expose\n    \n    add = -\u003e(x, y) { x + y }.curry\n    instance_methods.include?(:add) #=\u003e false\n    \n    expose :add, add\n    instance_methods.include?(:add) #=\u003e true\n  end\n  \n  include StdMath\n  \n  add[3, 4] #=\u003e 7\n  ```\n\n## 4. Examples\n\n- [examples/fizz_buzz.rb](examples/fizz_buzz.rb) - Examples of basic functional programming, basic IO, Maybe, fmap\n- [examples/repl.rb](examples/repl.rb) and [examples/whileM.rb](examples/whileM.rb) - Custom includable modules, looping, more nuanced use of IO\n- [examples/ruby_2.7_pattern_matching.rb](examples/ruby_2.7_pattern_matching.rb) - Using Maybe with the experimental pattern matching syntax in Ruby 2.7\n- [examples/rackio/](examples/rackio/) - A small Rack application built using Rubio; uses the StateIO monad to store data in memory that persists between requests\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F12joan%2Frubio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F12joan%2Frubio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F12joan%2Frubio/lists"}