[Functional Programming] Introduction to State, thinking in State
Recently, I am learning Working with ADT.
Got some extra thought about State Monad. Basiclly how to thinking in State.
First, we need to know the type of State: State returns Pair with Unit on the left, and state on the right:
State(state => Pair(Unit, state))
We don't need to manully add Pari and Unit type, State provides helper methods for doing this, but it is important to understand.
On the left side, Unit is a variable, types can be very depends on your needs.
On the right side, state has to be a fixed type, you better do NOT change it.
To access right side 'state', we can using 'modify' or 'set' helpers.
To access left side 'Unit', we can using 'get' helper.
One benifit by using State, is that we got lazyness for the function, means we can chain different state transition together.
Let's see an example:
const State = require('crocks/State');
const {get, modify} = State;
// add :: Int -> Int -> Int
const add = x => y => y + x;
// if we want to chain state transform, we need to have a function
// addNickel :: () -> State Int ()
//const addNickel = () => State(s => Pair(Unit(), s + 5))
const addNickel = () => modify(add());
// addDime = () -> State Int ()
const addDime = () => modify(add());
const addQuarter = () => modify(add());
In the example, we define three 'addXX' functions, each add different values.
We can compose them together:
// state :: State Int()
const state = addNickel()
.chain(addDime) // Pair( (), 15 )
.chain(addQuarter) // Pair( (), 40 )
.chain(addQuarter) // Pair( (), 65 )
.chain(addQuarter) // Pair( (), 90 )
.chain(addQuarter) // Pair( (), 115 ) console.log(
state
.runWith()
)
It is important to call 'runWIth', 'execWith' or 'evalWith'... because State is lazy, you need to trigger it. We chain multi state together to get new state, or let's saying we are keep modfiying the state. At this point, we didn't touch the 'Unit' part.
Then why 'Unit' / left side part can be useful?
We can think 'Unit' / left side part is the result of 'state' / right side part after mapping to some logic / function.
For example, we want to build a function, only return True of False, if number is greater than 100, return True, otherwise return False:
// canVend :: Int -> Boolean
const canVend = n => n >= ; console.log(
get()
.map(canVend)
.runWith()
) // False console.log(
get()
.map(canVend)
.runWith()
) // True
For calling 'get()', we are targeting left side part, which is 'Unit', it waiting some mapping function, which can transform state and put result into Unit. If we don't provide any mapping function, 'get()' will just copy the value from 'state':
console.log(
get()
.runWith()
) // Pair(10, 10) console.log(
get()
.map(x => x * )
.runWith()
) // Pair(20, 10) // the same as:
console.log(
get(x => x * )
.runWith()
) // Pair(20, 10)
In 'addNickle' example, we want to only get result in Boolean, if the state is greater than 100 or not, we can keep the state transform part untouched, only chain the getter logic in final state.
// canVend :: Int -> Boolean
const canVend = n => n >= ; // evaluate :: () -> State Int Bool
const evaluate = () => get(canVend); // get().map(fn) === get(fn) // state :: State Int()
const state = addNickel()
.chain(addDime) // Pair( (), 15 )
.chain(addQuarter) // Pair( (), 40 )
.chain(addQuarter) // Pair( (), 65 )
.chain(addQuarter) // Pair( (), 90 )
.chain(addQuarter) // Pair( (), 115 ) console.log(
state
.chain(evaluate)// Pair( true, 115 )
.runWith()
)
Full Code:
---
const State = require('crocks/State');
const {get, modify} = State;
// add :: Int -> Int -> Int
const add = x => y => y + x;// if we want to chain state transform, we need to have a function
// addNickel :: () -> State Int ()
//const addNickel = () => State(s => Pair(Unit(), s + 5))
const addNickel = () => modify(add());
// addDime = () -> State Int ()
const addDime = () => modify(add());
const addQuarter = () => modify(add());
// canVend :: Int -> Boolean
const canVend = n => n >= ;
// evaluate :: () -> State Int Bool
const evaluate = () => get(canVend); // get().map(fn) === get(fn)
// state :: State Int()
const state = addNickel()
.chain(addDime) // Pair( (), 15 )
.chain(addQuarter) // Pair( (), 40 )
.chain(addQuarter) // Pair( (), 65 )
.chain(addQuarter) // Pair( (), 90 )
.chain(addQuarter) // Pair( (), 115 )
console.log(
state
.chain(evaluate)// Pair( true, 115 )
.runWith()
)
[Functional Programming] Introduction to State, thinking in State的更多相关文章
- [Functional Programming] Using ComposeK for both get State and modify State
We have State like this: const state = { cards: [ { id: "green-square", color: "green ...
- [Functional Programming + React] Provide a reasonable default value for mapStateToProps in case initial state is undefined
For example we have a component, it needs to call 'react-redux' connect function. import { compose, ...
- [Functional Programming ADT] Initialize Redux Application State Using The State ADT
Not only will we need to give our initial state to a Redux store, we will also need to be able to re ...
- [Functional Programming Monad] Combine Stateful Computations Using A State Monad
The true power of the State ADT really shows when we start combining our discrete, stateful transact ...
- [Functional Programming Moand] Update The State Of A State Monad (put)
Stateful computations require the ability for their state to change overtime. We take a look on one ...
- [Functional Programming] Randomly Pull an Item from an Array with the State ADT (Pair)
Functor composition is a powerful concept that arises when we have one Functor nested in another Fun ...
- [Functional Programming] Transition State based on Existing State using the State ADT (liftState, composeK)
While sometimes outside input can have influence on how a given stateful transaction transitions, th ...
- Beginning Scala study note(4) Functional Programming in Scala
1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...
- Functional programming
In computer science, functional programming is a programming paradigm, a style of building the struc ...
随机推荐
- 【Go命令教程】10. go fix 与 go tool fix
命令 go fix 会把指定 代码包 的所有 Go 语言源码文件中的旧版本代码修正为新版本的代码.这里所说的版本即 Go 语言的版本.代码包的所有 Go 语言源码文件不包括其子代码包(如果有的话)中的 ...
- 浅析CentOS和RedHat Linux的区别
CentOS的简介 CentOS是Community ENTerprise Operating System的简称,我们有很多人叫它社区企业操作系统,不管你怎么叫它,它都是Linux操作系统的一个发行 ...
- AngularJS订阅API服务
本篇使用AngularJS实现订阅某个API服务. 首页大致是: 其中,what's on显示首页内容,Search通过输入关键词调用API服务显示到页面,MyShows显示订阅的内容. Sarch页 ...
- 玩一下C#的语音识别
在.NET4.0中,我可以借助System.Speech组件让电脑来识别我们的声音. 以上,当我说"name",显示"Darren",我说"age&q ...
- 解决iframe加载的内容有时显示有时不显示
在ASP.NET MVC项目中遇到了这样的一个问题,假设父页面有一个iframe <iframe id=" width="100%" height="10 ...
- delphi实现数字签名
上周,另一部门需要支援解决数字签名问题.但因为之前也没做过,现学现卖.此方面可参考的中文资料较少,特作分享,方便查阅. 上周,另一部门需要支援解决数字签名问题.但因为之前也没做过,现学现卖.此方面可参 ...
- panel内嵌程序窗体
function RunAppInPanel(const AppFileName: string; ParentHandle: HWND; var WinHandle: HWND): Boolean; ...
- file is universal (4 slices) but does not contain a(n) armv7s slice
关于ld: file is universal (2 slices) but does not contain a(n) armv7s slice 升级了xcode之后,支持iOS6和iPhone5, ...
- C#编程(二十八)----------泛型类的功能
泛型类的功能 在创建泛型类时,还需要一些其他的C#关键字.例如,不能把null赋予泛型类型.此时,可以使用default关键字.如果泛型类型不需要object类的功能,但需要调用泛型类上的某些特定方法 ...
- Oracle 导入导出 dmp 文件
导入dmp文件,需要知道这个dmp文件创建的用户.因此需要先创建用户,并授权给它. (1)用户的创建 首先,以system用户登录Oracle SQL Developer 其次,在sql工作表(可以用 ...