Upgrade to Pro — share decks privately, control downloads, hide ads and more …

蛇を蟹っぽくお型付け

E5d9758b3b8026448555b9e907d88920?s=47 wolf_cpp
December 18, 2019

 蛇を蟹っぽくお型付け

E5d9758b3b8026448555b9e907d88920?s=128

wolf_cpp

December 18, 2019
Tweet

Other Decks in Technology

Transcript

  1. 蛇を蟹っぽくお型付け wolf-cpp / CADDi, Inc.

  2. import me me.company = ‘キャディ株式会社’ me.language = [‘python’, ‘rust’, ‘cpp’]

    me.hobby = [‘violin’, ‘coffee’] me.age = 23 me.nickname = [ ‘きむD’, ‘をるふちゃん’ ] # NOTE: 重要 me.twitter = ‘@wolf_cpp’ # -*- coding: utf-8 -*-.
  3. import おしごと 製造業における社会課題をテクノロジーで解決する 見積もり算出のシステム化 → 3D図面自動注文 品質・価格・納期の最適化 → 確定発注 一括発注で調達担当者さまの負担減

  4. おしごと.wolf_cpp 見積もりの計算システムのコアを担当 -型安全で -計算の過程が式木(expression_tree)として出力 -SI+Jpy単位を扱える・自動変換されること -セグフォしないこと

  5. かなしみ.rs Rustしか選択肢なくね? いや。いいんだけどね。

  6. Rustよくわからんてひと • データの所有権という概念がある → データを変数間で共有することはできない • コードをコンパイルし、OSで直接実行可能なバイナリを吐く(LLVM基盤を利用) • C++より実行が速いかもしれん •

    トレイトによって型が提供しなければいけない機能を強制できる 所有権とトレイトがめっちゃむずかしい。つらい。
  7. しかし.py コスト計算システムのサーバができてきた → テストツールが必要 正となるデータはビジネスサイドからExcelで提供されるよ!(白目) これはPythonの出番 (☝ ՞ਊ ՞)☝

  8. 書いてみた if coating_type == ‘メラミン樹脂塗装’: coating_type = ‘melamine_resin’ elif coating_type

    == ‘アクリル樹脂塗装’: coating_type = ‘acrylic_resin’ elif coating_type == ‘ポリウレタン樹脂塗装’: coating_type = ‘polyurethane_resin’ elif coating_type == ‘粉体塗装’: coating_type = ‘powder_resin’ else: raise CoatingError(“無いよそんな塗装”)
  9. 問題点 しょうがないのはわかってるけどさ switch文がないのはやっぱりつらい 10個くらいelifを連鎖させているうちにwolf-cppは考えました。 なんでPythonにはmatch式がないんだろう、と。

  10. Rustのmatch式 match x { 1 => println!("one"), 2 => println!("two"),

    3 => println!("three"), 4 => println!("four"), 5 => println!("five"), _ => println!("something else"), }
  11. Python版 案① def match(var, matches, *, default): return matches[var] if

    var in matches else default a = 12 res = match(a, { 1 : 'a', 12 : 'b', 123 : 'c', }, default = 'd',)
  12. Python版 案② def match_apply(var, matches, *, default): return matches[var](var) if

    var in matches else default() a = 123 match_apply(a, { 1 : lambda x: print('a'), 12 : lambda x: print('b'), 123 : lambda x: print('c'), }, default = lambda x: print('d'),)
  13. 書いてみた if not outer_diameter: outer_diameter = ‘0’ if not inner_diameter:

    inner_diameter = ‘0’ request_pb.thickness = str( float(outer_diameter) – float(inner_diameter) ) def empty_to_zero(in): if not in: in = ‘0’ request_pb.thickness = str( float( empty_to_zero(outer_diameter) ) – float( empty_to_zero(inner_diameter) ) ) ------------------------------------------------------
  14. 問題点 型安全じゃないのはいったん目をつぶろう 変換掛けたくなるたびに両側にカッコをつけるのがつらい Ctrl + LeftArrow を連打 (あるいはHome Key)してるうちにwolf-cppは考えました。 ドット演算子かなんかでつなげて書けないのかと。

  15. • 変数をラップするクラス • Pythonは参照で変数をしばき倒す仕様なので copy.deepcopy を利用 https://gist.github.com/wolf-cpp/09ed5df41294c49d94706813bfecef05 手が滑って謎ライブラリを生やした class Var:

    def __init__(self, item): self.value = copy.deepcopy(item.value) if isinstance(item, Var) else copy.deepcopy(item)
  16. https://gist.github.com/wolf-cpp/09ed5df41294c49d94706813bfecef05 castをメソッドで生やした def cast(self, t): return Var( t( copy.deepcopy(self.value) )

    ) # キャストに失敗したら第二引数の値を返す def try_cast(self, t, default_value): try : res = t( copy.deepcopy(self.value) ) except (ValueError): res = default_value return Var( res )
  17. https://gist.github.com/wolf-cpp/09ed5df41294c49d94706813bfecef05 castをメソッドで生やした arr = [Var(‘’), Var(‘1’), Var(‘12’) for i in

    arr: i.cast(int) -------- arr = [Var(‘’), Var(‘1’), Var(‘12’) for i in arr: i.try_cast(int, 0) ValueError: invalid literal for int() with base 10: '' OK!
  18. https://gist.github.com/wolf-cpp/09ed5df41294c49d94706813bfecef05 map, apply def apply(self, fn): self.value = fn(self.value) return

    self def match(self, input_dict, *, default): return Var( match(self.value, input_dict, default=default) ) # matchに失敗したら元の値を返す def try_match(self, input_dict): return Var( match(self.value, input_dict, default=self.value) )
  19. https://gist.github.com/wolf-cpp/09ed5df41294c49d94706813bfecef05 map, apply a = Var(2) a.map({ 1: ‘a’, 2:

    ‘b’, 3: ‘c’, }, default= ‘d’) b = Var(100) b.apply( lambda x: x**2 ) c = Var(3) c.try_map({ 1: ‘e’, 2: ‘f’, 3: ‘g’, }) b 3 10000
  20. https://gist.github.com/wolf-cpp/09ed5df41294c49d94706813bfecef05 Nimっぽいって言われた。 def print(self): print(self.value) return self • Selfを返すことで、そのままつなげて書けるよ! c

    = Var(‘bar’) c.try_map({ ‘foo’: 1, ‘bar’: ‘2’, ‘baz’: 3, }).print() 2
  21. そして地獄のoperator定義

  22. Q. Rustっぽいだと? 所詮ダックタイピングだろ

  23. Q. Rustっぽいだと? 所詮ダックタイピングでしょ A. せやな……実装してやんよ

  24. None
  25. https://gist.github.com/wolf-cpp/09ed5df41294c49d94706813bfecef05 __set_attr__ でちょっと黒魔術 • setattr(object, name, value) • オブジェクト、文字列、任意の値を渡す。 •

    setattr(x, ‘foobar’, 123) は x.foobar = 123 と等価 • つまり、この関数をオーバーロードしてあげれば 「代入しようと思った??ざんねーん!!」 みたいなこともできる。
  26. __set__attr__の中で = で代入することはできない(set_attrが再帰的に呼ばれちゃう) object.__setattr__(self, ‘変数名’, 値) で代入する また、クラスのメンバ変数にアクセスしたければ以下のようにする self.__dict__[‘変数名’] これは以下の文と等価

    self.変数名
  27. 完成したクラス a = Var(100) a.value = 1 a.print() b =

    TypeSafe(‘a’) b.value = 2 1 AttributeError: TypeSafe class does not allow assignment wrong type: `TypeSafe.value (<class 'str'>) = 2 (<class 'int'>)`
  28. おまけ • 実はさっきのクラス TypeSafe の第2引数 mut を False にすると 再代入そのものが禁止になる仕様

    b = Const(‘a’) b.value = ‘b’ AttributeError: const-TypeSafe does not allow re- assignment to `value`
  29. 上司に見せたら

  30. 上司に見せたら それ以上聞きたくないって言われた。。。 (´・ω・`)

  31. print(‘Thank you!’)