livesense tech night immutable-js at a glance

47
Immutable @ JavaScript

Upload: yuta-shimakawa

Post on 17-Jul-2015

585 views

Category:

Engineering


3 download

TRANSCRIPT

Page 1: Livesense tech night   immutable-js at a glance

Immutable @ JavaScript

Page 2: Livesense tech night   immutable-js at a glance

var  me  =  {      name:      "Yuta  Shimakawa",      tw:          "@banana_umai",      qiita:    "bananaumai",      github:  "bananaumai"  };

Page 3: Livesense tech night   immutable-js at a glance
Page 4: Livesense tech night   immutable-js at a glance

ではございません

Page 5: Livesense tech night   immutable-js at a glance
Page 6: Livesense tech night   immutable-js at a glance

at a glance...

Page 7: Livesense tech night   immutable-js at a glance
Page 8: Livesense tech night   immutable-js at a glance

不変データ

Seq List Map

OrderedMap Set

OrderedSet Record

Page 9: Livesense tech night   immutable-js at a glance

var  list1  =  Immutable.List.of(1,  2);  var  list2  =  list1.push(3,  4,  5);  var  list3  =  list2.unshift(0);  var  list4  =  list1.concat(list2,  list3);  assert(list1.size  ===  2);  assert(list2.size  ===  5);  assert(list3.size  ===  6);  assert(list4.size  ===  13);  assert(list4.get(0)  ===  1);  

https://github.com/facebook/immutable-js/

Page 10: Livesense tech night   immutable-js at a glance

JSオブジェクトとの 相互変換

Page 11: Livesense tech night   immutable-js at a glance

var  map1  =  Immutable.Map({a:1,  b:2,  c:3,  d:4});  var  map2  =  Immutable.Map({c:10,  a:20,  t:30});  var  obj  =  {d:100,  o:200,  g:300};  var  map3  =  map1.merge(map2,  obj);  //  Map  {  a:  20,  b:  2,  c:  10,  d:  100,  t:  30,  o:  200,  g:  300  }

https://github.com/facebook/immutable-js/

var  deep  = Immutable.Map(  {  a:  1,  b:  2,  c:  Immutable.List.of(3,  4,  5)  });  

deep.toObject()  //  {  a:  1,  b:  2,  c:  List  [  3,  4,  5  ]  }  deep.toArray()  //  [  1,  2,  List  [  3,  4,  5  ]  ]  deep.toJS()  //  {  a:  1,  b:  2,  c:  [  3,  4,  5  ]  }  JSON.stringify(deep)  //  '{"a":1,"b":2,"c":[3,4,5]}'

Page 12: Livesense tech night   immutable-js at a glance

入れ子データ

Page 13: Livesense tech night   immutable-js at a glance

var  nested  =  Immutable.fromJS({a:{b:{c:[3,4,5]}}});  //  Map  {  a:  Map  {  b:  Map  {  c:  List  [  3,  4,  5  ]  }  }  }  

var  nested2  =  nested.mergeDeep({a:{b:{d:6}}});  //  Map  {  a:  Map  {  b:  Map  {  c:  List  [  3,  4,  5  ],  d:  6  }  }  }  

var  nested3  =  nested2.updateIn(['a',  'b',  'd'],  value  =>  value  +  1);  

//  Map  {  a:  Map  {  b:  Map  {  c:  List  [  3,  4,  5  ],  d:  7  }  }  }  

var  nested4    =  nested3.updateIn(['a',  'b',  'c'],  list  =>  list.push(6));  

//  Map  {  a:  Map  {  b:  Map  {  c:  List  [  3,  4,  5,  6  ],  d:  7  }  }  }

https://github.com/facebook/immutable-js/

Page 14: Livesense tech night   immutable-js at a glance

遅延評価(Seq)

Page 15: Livesense tech night   immutable-js at a glance

var  oddSquares  =  Immutable.Seq.of(1,2,3,4,5,6,7,8)                                      .filter(x  =>  x  %  2)                                      .map(x  =>  x  *  x);  //  not  computed  here!      oddSquares.get(1);  //  9

https://github.com/facebook/immutable-js/

Page 16: Livesense tech night   immutable-js at a glance

同等性

Page 17: Livesense tech night   immutable-js at a glance

var  map1  =  Immutable.Map({a:1,  b:1,  c:1});  var  map2  =  Immutable.Map({a:1,  b:1,  c:1});  assert(map1  !==  map2);  assert(Immutable.is(map1,  map2)  ===  true);

https://github.com/facebook/immutable-js/

Page 18: Livesense tech night   immutable-js at a glance

JSで不変データ

Page 19: Livesense tech night   immutable-js at a glance

Immutableなリストを 素朴に実装してみた

Page 20: Livesense tech night   immutable-js at a glance

cloneによる実装

Page 21: Livesense tech night   immutable-js at a glance

var  _  =  require('lodash');      function  iPush(arr,  val)  {      var  arr2  =  _.clone(arr);      arr2.push(val);      return  arr2;  }      var  arr  =  [];  for  (var  i  =  0;  i  <  100000;  i++)  {      arr  =  iPush(arr,  i);  }

https://gist.github.com/bananaumai/cc2f4d90662aa823ce9e

Page 22: Livesense tech night   immutable-js at a glance

…は cloneのコストが膨大

Page 23: Livesense tech night   immutable-js at a glance

Linked Listを実装

Page 24: Livesense tech night   immutable-js at a glance

var  LinkedList  =  {};  LinkedList.prototype  =  {      head:  function()  {          return  this._head;      },          tail:  function()  {          return  this._tail;      },          push:  function(val)  {          return  new  NonEmptyList(val,  this);      },          forEach:  function(fnc)  {          fnc(this._head);          if  (this._tail  instanceof  NonEmptyList)  {              this._tail.forEach(fnc);          }      }  };  

var  EmptyList  =  function()  {      this._head  =  null;      this._tail  =  null;  };  EmptyList.prototype  =  Object.create(LinkedList.prototype);  EmptyList.prototype.constructor  =  EmptyList;

https://gist.github.com/bananaumai/164b24b264e0f917007c

var  NonEmptyList  =  function(head,  tail)  {      this._head  =  head;      this._tail  =  tail;  };  NonEmptyList.prototype  =  Object.create(LinkedList.prototype);  NonEmptyList.prototype.constructor  =  NonEmptyList;    

LinkedList.of  =  function()  {      var  _create  =  function(vals,  list)  {          if  (vals.length  ===  0)  return  list;          var  head  =  vals.shift();          return  _create(vals,  new  NonEmptyList(head,  list))      };          return  _create(          Array.prototype.slice.call(arguments).reverse(),          new  EmptyList()      );  };

Page 25: Livesense tech night   immutable-js at a glance

var  list  =  LinkedList.of();  for  (var  i  =  0;  i  <  100000;  i++)  {      list  =  list.push(i);  }  

https://gist.github.com/bananaumai/164b24b264e0f917007c

Page 26: Livesense tech night   immutable-js at a glance

…は (&pushはそれなりに速いけど・・・)

末尾再帰最適化 されないので難しい (&Object.ArrayのAPIの実現しようとすると・・・)

Page 27: Livesense tech night   immutable-js at a glance

immutable-jsのアプローチ

Page 28: Livesense tech night   immutable-js at a glance

Trie

http://ja.wikipedia.org/wiki/%E3%83%88%E3%83%A9%E3%82%A4%E6%9C%A8

Page 29: Livesense tech night   immutable-js at a glance

(def  list  [0  1  2  3  4  5])

Page 30: Livesense tech night   immutable-js at a glance

ClojureやScalaが採用 しているアプローチ

Page 31: Livesense tech night   immutable-js at a glance
Page 32: Livesense tech night   immutable-js at a glance

Immutable.Listの実装

Page 33: Livesense tech night   immutable-js at a glance

文字列のキーの代わりに 添字の数値をbitに変換、パーティショニング

Page 34: Livesense tech night   immutable-js at a glance

var  list  =  Immutable.List.of(1,…,1000);  list.get(887);

http://hypirion.com/musings/understanding-persistent-vector-pt-2#f1n

Page 35: Livesense tech night   immutable-js at a glance

実際は5bitずつ分割するので ↓

O(Log32N)

Page 36: Livesense tech night   immutable-js at a glance

実際は32通り

http://hypirion.com/musings/understanding-persistent-vector-pt-1

Page 37: Livesense tech night   immutable-js at a glance

var  list1  =  Immutable.List.of(1,2,3,4,5,6,7,8);  var  list2  =  list1.set(5,  "beef");

list1 list2

http://hypirion.com/musings/understanding-persistent-vector-pt-1

Page 38: Livesense tech night   immutable-js at a glance

要素のpushvar  list1  =  Immutable.List.of(…);  var  list2  =  list.push(…);

Page 39: Livesense tech night   immutable-js at a glance

最右のリーフノードに空きがある場合

http://hypirion.com/musings/understanding-persistent-vector-pt-1

Page 40: Livesense tech night   immutable-js at a glance

最右のリーフノードに空きがない場合

http://hypirion.com/musings/understanding-persistent-vector-pt-1

Page 41: Livesense tech night   immutable-js at a glance

rootから伸びるすべてのリーフが埋まっている場合

http://hypirion.com/musings/understanding-persistent-vector-pt-1

Page 42: Livesense tech night   immutable-js at a glance

要素のpopvar  list1  =  Immutable.List.of(…);  var  list2  =  list.pop();

Page 43: Livesense tech night   immutable-js at a glance

最右のリーフノードが2つ以上の要素を持つ場合

http://hypirion.com/musings/understanding-persistent-vector-pt-1

Page 44: Livesense tech night   immutable-js at a glance

最右のリーフノードが1つの要素を持つ場合

http://hypirion.com/musings/understanding-persistent-vector-pt-1

Page 45: Livesense tech night   immutable-js at a glance

削除後rootノードが1つの要素だけをもつ場合

http://hypirion.com/musings/understanding-persistent-vector-pt-1

Page 46: Livesense tech night   immutable-js at a glance

簡単なまとめ

Page 47: Livesense tech night   immutable-js at a glance

Trieによるリストの表現 O(Log32N)のアクセス 最小限のコピー