c4se記:さっちゃんですよ☆

.。oO(さっちゃんですよヾ(〃l _ l)ノ゙☆)

.。oO(此のblogは、主に音樂考察Programming に分類されますよ。ヾ(〃l _ l)ノ゙♬♪♡)

音樂は SoundCloud に公開中です。

考察は現在は主に Scrapbox で公表中です。

Programming は GitHub で開發中です。

ヨコガナの紹介

英語を書くのであれば Latin 文字とアラビア數字を使って左から右へ書く。日本語は長年の書き方の變化を結構保存してゐて、書字方向は上から下への縱書きと左から右への横書き、半世紀ほど前であれば又今でもトラックの側面等に右から左への横書きを使ふ。字の種類には先ず漢字が在り、漢字には略字を含め舊字體と新字体が在るし、慣れてゐない人間から見ると楷書體と草書體とが同じ字だと云ふ事は判りづらい。かな文字にひらがなとカタカナが在り、更に Latin 文字とアラビア數字も多用する。私は普段文を手書きしてゐ、先の內で日々使ってゐるのは、漢字 (新字体)、ひらがな、カタカナ、Latin 文字 + アラビア數字である。これに加えて私は「ヨコガナ」と「縦 Latin」と云ふ文字を使ってゐる。このヨコガナを紹介したい。

ヨコガナはかな文字であり、ひらがなやカタカナと同種のものだ。「ヨコガナ」と云ふ語をヨコガナで書くとかう成る。

ヨコガナ

ヨと書きコと書きカに濁點が附きナと書いてある。ヨコガナの字はひらがなやカタカナの字と一對一に對應する。

ヨコガナは私の知人が作った字で、私が使ってゐるものはそれとは幾つか字の形を變へてある。ひらがなの替はりに作られた文字だ。ひらがなは昔日本語を縦に連綿して書く樣に使はれ始め、縦に速く美しく書く事が出來る。ここ半世紀ほどで日本語が左から右へ橫に書かれるやうに成り、ひらがなも橫に書かれるやうになった。手書きでも橫である。この時迄にひらがなは活字體を基に作り直され、連綿せず一字づつ離して書く事が多く成った。かう成ったひらがなを速く且つ美しく書く方法は自明ではなく、各人が各人の工夫を凝らしてきた (丸文字はその工夫の一つであらう)。私の知人はそこにもう一つ、各人の工夫を編み出したのである。

ヨコガナはかなを連綿して書けるやう、Latin やキリルの筆記體を參考にしてかな文字を置き換へてある。對應表が有るから載せよう。

友人に依るもの。

カタカナ → ヨコガナ對應表 1

私のもの。

カタカナ → ヨコガナ對應表 2

一字づつ紹介するのも興味深いが、これはもう書けば覺えるのであるから、書例を載せる事で代へる。書例は Pinterest に集めてある。

ヨコガナ

ヨコガナは好く出來てあり、書く者毎に字の形をそれなりに自由に出來るやうに成ってゐる。アの高さを私はタの高さ迄上げて書くが、友人はイと同じ高さで書く。ケの第一畫を友人はアラビア數字の 2 のやうに丸めるが、私は鋭角に角ばらせる。ニに在る s のやうな形は上から下ろしても好いし、下から跳ね上げても好い。ルの第ニ畫も同じく言へる。等。これらで字の印象は可成り變はる。辨別が出來る限りは書き易い形を見附けて書くのが好いと思ふ。

雜=多樣性と云ふ概念の假説

雜と云ふ在り方の概念を重視出來るのではないかと云ふ考へを育ててゐる。はっきりと際立った概念ではないが、雜をどう定めるのが好いかと云ふ假説は持って有り、細分を續けても常に更に細分出來る狀態である在り方を雜と名附けやうとしてゐる。私は今 programmer として在り、いわく定め難い team と云ふ集まりで過ごしてゐる。此う云った生活に適合してゆく事と、私が古く育んだ考へとを繋げる事が出來ず、其の成り行きでどうしたら眞である事が出來るかを長く考へ、長く考へ過ぎてゐるが、其所で眞と主體は近い形をしてゐると考へるやうに成った (發言の超越論的な根拠)。其の反対側である、日々に適合すると云ふ側から雜と云ふ概念を考へればどこかで衝突するのではないかと思ってゐる。

假説としては二つが有る。

  • 多樣性と云ふ概念を重視出來るのではなからうか。
  • 其の多樣性と云ふ概念は上記で定まる雜と云ふ語で名附けるのが有効ではないか。

雜を上の樣に定める事は、言葉や認識や行為に依っては汲み尽くせない實在を考へる事に相當する。しかし體驗に依れば雜には過去に於ける蓄財が要り未來で蓄財を汲み出すと云ふ前提が要る。此れは雜が感覺に依って汲み尽くされないものではあるがしかし感覺されるものである、或いは感覺されるものでもあるからだと思ふ。蓄財が尽きれば雜は在り方から去って了ふ。

名實の組みを建てるならば、名を先に取り名 (普遍) が在れば對應する實が實在する、不當な名は名同士の關係で定まると云ふ考へ (礼) と、實を先に取り實 (個物) に適切な名を附ける、不當な名は實が無い事で定まると云ふ考へ (生得) が在る。雜はどちらでもない。雜は不當な名の不當さが一意である事を更に細分する。名が名である事と實が實である事は名實に於いては一意であり、雜は其の一意である事を更に細分する。此の細分は手續きであり終はらない手續きであるから過ぎゆくものとしての時間である。そこで雜は蓄財と汲み尽くしと云ふ形で瞬間であり、細分と云ふ形で時間である。

此の記事や考へそのものが、より基になる根拠が無いと云ふ事で雜であるが、日常の考へ方を素直に氣遣ひ延ばしてゆくと云ふ事ではストア派風ではある。此の素直と云ふ概念は、似てゐるものを似てゐるとし似てゐないものを似てゐないとすると云ふ風に定まると考へてゐた事が有った。今は好く解らない。

Develop Google Apps Script in ClojureScript

qiita.com🎂

What is Google Apps Script?

f:id:Kureduki_Maari:20181223190842p:plain

Google Apps Script (以下 Apps Script) は、Google の server 上での serverless な JavaScript 實行環境です。serverless な JavaScript 實行環境ですので Cloud Function の仲間です。函數を起動できる event の種類が限られている、また SLA (Service Level Agreement) が不明である為、Cloud Function のやうに大規模な servise を作る事は、できません。代はりに、Docs や Gmail 等[など]の Google Apps と連携するやう簡單に設定できる為、この意味で VBA (Visual Basic for Applications) の仲間でもあります。更に Google Apps が使へる環境であれば無料です。その代はり一日当りの實效囘數等が制限されてゐます。

Apps Script と云へば Google Apps 向けの VBA である、と思はれる向きもあり、Gmail と Spreadsheet を同時に見たり更新したりできると云ふ使ひ途もあるのですが、cron の代はりとして Google Apps に全く觸らない函數も作れます。であるので、Google Apps account で使へる serverless FaaS (Function as a Service) だと見るのがよいです。今の所書ける言語は JavaScript だけです。

Google Apps の web site 上に Apps Script の editor があるのですが、ただの text editor であり、version 管理も難しく、複數人で編集したり test を書いたり library を使ったりする事ができません。programmer ですので、日々使ってゐる editor (Emacs) で書き、日々使ってゐる version 管理 system (Git) で管理し、人間にも讀める code を書きたいものです。これをお膳立てしてくれるのが clasp です。

github.com

Apps Script 用の CLI tool であり、local の script を upload する、Google Apps 上の script を download する、Google Apps 上の script を實行する、Google Apps 上の現在の version に tag を打つ、Apps Script が吐いた log を見る、等の事ができます。まともな開發に要る事はできさうです。人間でゐませう (發狂せずとも濟みさうと云ふ意)。

What is ClojureScript?

f:id:Kureduki_Maari:20181223190914p:plain:w128

ClojureScript (a.k.a. cljs) は Clojure の實裝の一つです。Clojure と云へば JVM 上の Lisp の一つとして生まれましたが、その後.NET CLR 上でも實裝され、JavaScript への transpiler も作られました。この二つは Clojure と同じ或いは近しい community で作られてゐます。他にも Erlang VM 上で動くclojerlや、C に transpile するclojurec (これの開發は停まってゐます) もあります。廣く實行環境を見れば、Android 上で動かすlein-droid (これも開發が停まってゐます)、React Native で動かすRe-Natal、Unity で動くArcadia等があり、更には Graal で JVM 用の Clojure を native code に落とせるので (Graal が MySQL に搭載されたらそこでも動く) (clojure-clr を Mono LLVM に流すと云ふ手も在ります)、どこででも動きますね (Ethereum の contract 自體を書く方法は見附からないので EthereumVM では動きませんね)。CloduinoArduino も弄れるみたいです。珍しい所ではQuilから Processing で映像を描けたり、Overtoneから SuperCollider で音樂を生成したりできます。

Clojure は immutable な data を基礎とし、vector や map 等の data 構造 & 使ひ易い記法を持った Lisp です。Lisp である事が我々にとってはまづ一つの利点ですし、data が immutable ですから、program を抽象化し易く、concurrency を簡單に扱へます。ClojureScript は Clojure から JavaScript への transpiler です。JVMAPI は使へませんが、Clojure の core API の大半が使へますし、JavaScript を簡單に呼び出せます。無論 NPM も使へます。

Isomorphic と云ふ言葉は懐かしいですが、懐かしくなったからといって重要で無くなった譯ではありません。Reagent 等便利な Web frontend framework が在ります。

Develop Apps Script in ClojureScript.

以下の二つを install します。

  • cljs : Mac であればbrew install clojurescriptで ClojureScript を、或いはbrew install leiningenで Leiningen を入れて project 毎に install します。
  • clasp : NPM を入れ、npm install -g @google/claspで入れます。

私は Leiningen で project を作ったので、こんなproject.cljができます。

(defproject apple-is-dead "0.1.0"
  :description "Appleの障害情報を監視し通知する"
  :url "〜〜〜"
  :license {:name "Do What The F*ck You Want To Public License"
            :url "http://sam.zoy.org/wtfpl/COPYING"}
  :plugins [[jonase/eastwood "0.3.3"]
            [lein-ancient "0.6.15"]
            [lein-cljfmt "0.5.7"]
            [lein-cljsbuild "1.1.7"]]
  :dependencies [[org.clojure/clojure "1.9.0"]
                 [org.clojure/clojurescript "1.10.439"]]
  :hooks [leiningen.cljsbuild]
  :aliases {"lint" ["run", "-m" "apple-is-dead.tasks.lint/go"]
            "release" ["run", "-m" "apple-is-dead.tasks.release/go"]}
  :cljsbuild {:builds
              [{:source-paths ["src"]
                :compiler {:main apple-is-dead.main
                           :output-to "release/main.js"
                           :output-dir "target"
                           :optimizations :advanced
                           :pretty-print false
                           :foreign-libs [{:file "src/entrypoint.js"
                                           :provides ["apple-is-dead.entrypoint"]}]
                           :externs ["src/extern.js"]}}]})

lein-cljsbuild が、Leiningen に ClojureScript を build するやり方を教えます。

  :hooks [leiningen.cljsbuild]
  :cljsbuild {:builds
  〜〜〜

と hook すると、lein compileで ClojureScript の file である*.cljsを探して JavaScript に transpile します。

:aliasesの lint では

prettier --write src/*.js
lein cljfmt fix
lein ancient check
lein eastwood

のやうな事をさせてゐ、release では

lein compile
clasp push

のやうな事をさせてゐます。

作った ClojureScript の project 内でclasp create 〜〜〜を叩き、Apps Script project を作ります。この時に作られる file 達が大切なので、これらを cp しておき、これらが在る diractory で以後clasp command を叩きます。

あとは ClojureScript と Apps Script の referense を御覽ください。Apps Script では log を見たり error を mail に通知する事ができますので、そこを適切に作ると運用が樂になります。error を catch する時は(js/console.error err)で log を吐く、實行の重要な step 毎に(js/console.info message)で log を吐く、catch すべきでない error を catch しない、retry されてもよいやうに冪等にする等、batch 處理を書く時と似た事を注意する筈です。

:foreign-libs:externsは載せておきます。

                           :foreign-libs [{:file "src/entrypoint.js"
                                           :provides ["apple-is-dead.entrypoint"]}]
                           :externs ["src/extern.js"]

:foreign-libsJavaScript から ClojureScript を呼ぶ時に要ります。Apps Script は書かれたものが JavaScript であらうと前提して呼び出しますから、JavaScript 側から呼べる interface を開けておかなければなりません。ここに指定した file に JavaScript を書いておくと、それは Closure Compiler (ClojureScript が Closure Compiler を呼び出して、code を圧縮したり dead code を消したりします) で變換されずに、出力される JavaScript にそのまま載ります。

// entrypoint.js
function main(evt) {
  apple_is_dead.main.main();
}
; main.cljs
(defn ^:export main []
  (doseq [service ((apple.get-status) :services)]
    (check-apple-service service)))

これで Apps Script はmain()を呼び出せ、それによりapple_is_dead.main.main()、すなはち(apple-is-dead.main.main)を實行できます。

:externsは、Closure Compiler が圧縮してはいけない變數名を列擧する file です。これらは外の環境に global に定義されてゐるから、このままの名前で呼び出さなければならない、例えば JavaScript の core に定義された module 達ですが、これらはどうやら Closure Compiler が既に知ってゐます。しかし Closure Compiler は Apps Script の事は知りません。それでも Closure Compiler はたいていうまくやりますが、一部見逃してしまふやうです。私の場合はCacheServiceの事は教えてやらねばなりませんでした (他にも色々呼び出したのですが、これ以外はうまく、圧縮せずにゐてくれました) (Closure Script の實裝を読んでゐないのが惡いのですが)。

// extern.js
var CacheService = {};
CacheService.getScriptCache = function () {};

これで ClojureScript で Apps Script を開發できると思ひます。

The Best of Access @ Elixir

Immutable data is a foundation of abstraction - it localizes program computation. So immutable data makes concurrency easy & decreases bugs. All data in Erlang/Elixir is immutable. We are happy to use functional programming techniques, worrying about nothing on parallel programming.

To lookup in a nested data is easy. When there is a map below :

v = %{
  x: [
    {:ok, a: 1, b: 2},
    {:ok, a: 3, b: 4},
  ]
}

Following codes are same.

1 = elem(Enum.at(v.x, 0), 1)[:a]

1 = elem(Enum.at(v[:x], 0), 1)[:a]

1 = (v.x |> Enum.at(0) |> elem(1))[:a]

# We can pipe all.
1 = v |> Map.get(:x) |> Enum.at(0) |> elem(1) |> Keyword.get(:a)

1 = v |> Access.get(:x) |> Enum.at(0) |> elem(1) |> Access.get(:a)

1 = get_in(v.x, [Access.at(0), Access.elem(1)])[:a]

1 = get_in(v, [:x, Access.at(0), Access.elem(1), :a])

We can use pattern matching too.

1 = with %{x: [{:ok, a: a, b: _} | _]} = v, do: a

1 = case v, do: (%{x: [{:ok, a: a, b: _} | _]} -> a)

true = match?(%{x: [{:ok, a: 1, b: _} | _]}, v)

But it's hard to UPDATE a nested data.

v_2 = Map.update!(v, :x, fn x ->
  List.update_at(x, 0, fn {:ok, k} ->
    {:ok, Keyword.update!(k, :a, &(&1 + 1))}
  end)
end)

1 = elem(Enum.at(v.x, 0), 1)[:a]
2 = elem(Enum.at(v_2.x, 0), 1)[:a]

Why this's hard? The nested callback functions is complecated. It's not composable, so we can't split this into simple parts. Is there no way?

JavaScript - Immer

Let's see some examples in other languages.

Data in JavaScript isn't immutable. But after React & Redux comes, JavaScript loves immutability. Immer is a nice library to update nested data with immutability.

f:id:Kureduki_Maari:20181205120623p:plain

mweststrate/immer: Create the next immutable state by mutating the current one

import produce from "immer";

const v = {
  x: [
    ["ok", { a: 1, b: 2 }],
    ["ok", { a: 3, b: 4 }],
  ],
};

const v2 = produce(v, (v) => {
  v.x[0][1].a += 1;
});

assert.equal(v.x[0][1].a, 1);
assert.equal(v2.x[0][1].a, 2);

Data in JavaScript is mutable, so it has short syntax to update data. Immer use it. It Proxy the data, listen all mutation operations & create a new data. This's the way in a mutable language to update nested data with immutability.

Lens @ Haskell

f:id:Kureduki_Maari:20181205121329p:plain

Haskell is close to Elixir because data in Haskell is immutable. Haskell has a nice mechanism - Lens.

lens: Lenses, Folds and Traversals

microlens: A tiny lens library with no dependencies. If you're writing an app, you probably want microlens-platform, not this.

Lens is a set of functions of composable getter & setter.

{-# LANGUAGE TemplateHaskell #-}
import Lens.Micro
import Lens.Micro.TH

data Item = Item { _a :: Integer, _b :: Integer } deriving (Show)
makeLenses ''Item

data V = V { _x :: [(String, Item)] } deriving (Show)
makeLenses ''V

v = V {
  _x = [
      ("ok", Item { _a = 1, _b = 2 }),
      ("ok", Item { _a = 3, _b = 4 })
    ]
  }

main = do
  print $ v ^?! to _x . ix 0 . _2 . to _a
  -- 1

  print $ v ^?! x . ix 0 . _2 . a
  -- 1

  print $ v & x . ix 0 . _2 . a .~ 2
  -- V {_x = [("ok",Item {_a = 2, _b = 2}),("ok",Item {_a = 3, _b = 4})]}

  print $ v & x . ix 0 . _2 . a %~ (+ 1)
  -- V {_x = [("ok",Item {_a = 2, _b = 2}),("ok",Item {_a = 3, _b = 4})]}

  print $ v & (x . ix 0 . _2 . a) +~ 1
  -- V {_x = [("ok",Item {_a = 2, _b = 2}),("ok",Item {_a = 3, _b = 4})]}

Lens is just a function, so we can compose them & create custom Lens (makeLenses dose).

Clojure - a neighbor of Elixir

f:id:Kureduki_Maari:20181205121313p:plain

In ancient days Elixir was born from Clojure. So we look at that. Clojure is a functional language which is based on immutable data.

get-in, assoc-in & update-in are the basic tools to manipulate nested data.

(def v
  {:x [["ok" {:a 1, :b 2}] ["ok" {:a 3, :b 4}]]})

; get
; => 1
((((v :x) 0) 1) :a)
(:a (((:x v) 0) 1))
(:a (get (get (:x v) 0) 1))
(-> v :x (get 0) (get 1) :a)
(get-in v [:x 0 1 :a])
(let [{:keys [x]} v [[_ {:keys [a]}]] x] a)

; assoc
; => {:x [["ok" {:a 2, :b 2}] ["ok" {:a 3, :b 4}]]}
(update v :x (fn [x] (update x 0 (fn [i] (update i 1 (fn [j] (assoc j :a 2)))))))
(assoc-in v [:x 0 1 :a] 2)

; update
; => {:x [["ok" {:a 2, :b 2}] ["ok" {:a 3, :b 4}]]}
(update v :x (fn [x] (update x 0 (fn [i] (update i 1 (fn [j] (update j :a #(+ 1 %))))))))
(update-in v [:x 0 1 :a] #(+ 1 %))

Note assoc & update. Nested callbacks are transformed into a sequence of keys [:x 0 1 :a]. The sequence is just a data, so we can compose them.

Elixir has Access!

Like get-in, assoc-in & update-in in Clojure, Elixir has get_in/2, put_in/3, update_in/3 & pop_in/2.

v = %{x: [{:ok, a: 1, b: 2}, {:ok, a: 3, b: 4}]}

1 = get_in(v, [:x, Access.at(0), Access.elem(1), :a])

%{x: [{:ok, a: 2, b: 2}, {:ok, a: 3, b: 4}]} =
  put_in(v, [:x, Access.at(0), Access.elem(1), :a], 2)

%{x: [{:ok, a: 2, b: 2}, {:ok, a: 3, b: 4}]} =
  update_in(v, [:x, Access.at(0), Access.elem(1), :a], &(&1 + 1))

{1, %{x: [{:ok, b: 2}, {:ok, a: 3, b: 4}]}} =
  pop_in(v, [:x, Access.at(0), Access.elem(1), :a])

These are family of Access module. These take a "path", a sequence of keys & functions. Map & Keyword takes a key. List needs Access.at/1. Tuple needs Access.elem/1.

%{x: 2} = put_in(%{x: 1}, [:x], 2)
%{x: 2} = put_in(%{x: 1}[:x], 2)
%{x: 2} = put_in(%{x: 1}.x, 2)

[x: 2] = put_in([x: 1], [:x], 2)
[x: 2] = put_in([x: 1][:x], 2)

%{x: 1, y: 2} = put_in(%{x: 1}[:y], 2)

[y: 2, x: 1] = put_in([x: 1][:y], 2)

# `Access.key!/1` is also available for Map.
%{x: 2} = put_in(%{x: 1}, [Access.key!(:x)], 2)

try do
  put_in(%{x: 1}, [Access.key!(:y)], 2)
rescue
  err in KeyError -> err
end

try do
  put_in(%{x: 1}.y, 2)
rescue
  err in KeyError -> err
end

# `Access.key/2` provides a default value. This is useful for put_in & update_in.
%{x: 1, y: %{z: 2}} = put_in(%{x: 1}, [Access.key(:y, %{}), :z], 2)

# List
[2] = put_in([1], [Access.at(0)], 2)

nil = get_in([1], [Access.at(1)])

# Tuple
{2} = put_in({1}, [Access.elem(0)], 2)

You'll find that accessing Struct causes an error. Struct isn't accessible in default. But we can use Access.key!/1 & Access.key/2.

defmodule Example do
  defstruct x: 1
end

defmodule Main do
  def main do
    %Example{x: 2} = put_in(%Example{}, [Access.key!(:x)], 2)
    %Example{x: 2} = put_in(%Example{}, [Access.key(:x)], 2)
  end
end
Main.main

One of the best feature of Access is Access.all/0 & Access.filter/1. These reduce nested Enum calls. Access.all/0 traverses a List. Access.filter/1 traverses a List & filter them.

%{x: [%{a: 2}, %{a: 3}]} =
  update_in(%{x: [%{a: 1}, %{a: 2}]}.x, fn x -> for %{a: a} <- x, do: %{a: a + 1} end)

%{x: [%{a: 2}, %{a: 3}]} =
  update_in(%{x: [%{a: 1}, %{a: 2}]}, [:x, Access.all(), :a], &(&1 + 1))

require Integer

%{x: [%{a: 1}, %{a: 1}]} = update_in(
  %{x: [%{a: 1}, %{a: 2}]}.x,
  fn x ->
    x
    |> Enum.reduce(
      [],
      fn
        %{a: a}, accm when rem(a, 2) == 0 -> [%{a: div(a, 2)} | accm]
        i, accm -> [i | accm]
      end
    )
    |> Enum.reverse
  end
)

%{x: [%{a: 1}, %{a: 1}]} = update_in(
  %{x: [%{a: 1}, %{a: 2}]},
  [:x, Access.filter(&Integer.is_even(&1.a)), :a],
  &div(&1, 2)
)

Extend Access

There are 2 ways to extend Access.

  1. Create an Access fun
  2. @impl Access

Create an Access fun

We can create functions like Access.*/* by ourselves. It's called "access_fun".

access_fun(data, get_value) ::
  get_fun(data, get_value) | get_and_update_fun(data, get_value)

access_fun is an union of get_fun & get_and_update_fun.

get_fun(data, get_value) ::
  (:get, data, (term() -> term()) -> {get_value, new_data :: container()})

get_and_update_fun(data, get_value) ::
  (:get_and_update, data, (term() -> term()) ->
     {get_value, new_data :: container()} | :pop)

Let's create one. In a following situation,

v = %{x: [{:ok, a: 1, b: 2}, {:ok, a: 3, b: 4}]}

1 = get_in(v, [V.a(1), :a])

%{x: [{:ok, a: 2, b: 2}, {:ok, a: 3, b: 4}]} = put_in(v, [V.a(1), :a], 2)

%{x: [{:ok, a: 2, b: 2}, {:ok, a: 3, b: 4}]} = update_in(v, [V.a(1), :a], &(&1 + 1))

the access_fun will be this.

defmodule V do
  def a(a), do: fn command, data, next -> a(command, data, a, next) end

  defp a(:get, data, a, next) do
    data.x
    |> Enum.find(fn
      {:ok, x} -> x[:a] == a
      _ -> false
    end)
    |> elem(1)
    |> next.()
  end

  defp a(:get_and_update, data, a, next) do
    {{:ok, x}, i} =
      data.x
      |> Enum.with_index
      |> Enum.find({{:ok, nil}, nil}, fn
        {{:ok, x}, _} -> x[:a] == a
        _ -> false
      end)

    case next.(x) do
      {get, update} ->
        data = put_in(data, [:x, Access.at(i), Access.elem(1)], update)
        {get, data}

      :pop ->
        if is_nil(i) do
          data
        else
          {_, data} = pop_in(data, [:x, Access.at(i), Access.elem(1)])
          data
        end
    end
  end
end

access_fun pros :

  • It can traverse all data.
  • Separate from other Access behaviour.
  • You can write complex behaviour.

access_fun cons :

  • It has many boilerplate.
  • Too complex.

When you just want a short cut of Access path, you can implement a Access behaviour.

@impl Access

Access behaviour provides more fluent syntax for users. When a struct is, you should implement Access like this.

defmodule V do
  defstruct x: []

  @behaviour Access

  @impl Access
  def fetch(v, key) do
    case path_to(v, key) do
      nil -> :error
      path -> {:ok, get_in(v, path)}
    end
  end

  @impl Access
  def get_and_update(v, key, fun) do
    case path_to(v, key) do
      nil -> {nil, v}
      path -> get_and_update_in(v, path, &fun.(&1))
    end
  end

  @impl Access
  def pop(v, {_, _} = key) do
    case path_to(v, key) do
      nil -> {nil, v}
      path -> pop_in(v, path)
    end
  end

  defp path_to(v, {:a, a}) do
    with i when not is_nil(i) <-
      Enum.find_index(v.x, fn
        {:ok, x} -> x[:a] == a
        _ -> false
      end) do
      [Access.key!(:x), Access.at(i), Access.elem(1)]
    else
      _ -> nil
    end
  end
end

Easy. Then you can call this like natively supported syntax.

defmodule Main do
  def main do
    v = %V{x: [{:ok, a: 1, b: 2}, {:ok, a: 3, b: 4}]}

    1 = v[{:a, 1}][:a]

    %V{x: [{:ok, a: 2, b: 2}, {:ok, a: 3, b: 4}]} =
      put_in(v[{:a, 1}][:a], 2)

    %V{x: [{:ok, a: 2, b: 2}, {:ok, a: 3, b: 4}]} =
      update_in(v[{:a, 1}][:a], &(&1 + 1))

    {1, %V{x: [{:ok, b: 2}, {:ok, a: 3, b: 4}]}} =
      pop_in(v, [{:a, 1}, :a])
  end
end
Main.main

Access is composable & extensible abstraction to get & update deep nested data. Let's enjoy functional programming on Elixir!

ヨコガナ/縦Latin Advent Calendar 2018

ヨコガナ/縦 Latin Advent Calendar 2018 です。

毎日、橫假名/縱 Latin を書いて畫像を貼ります。募集もしてます。

應募先 : https://mstdn.res.ac/@ne_sachirou

今迄の書例は下記に在ります。

ももんが Advent Calendar の系譜 :

12/1

橫假名

f:id:Kureduki_Maari:20181201234848j:plain
いろはにほへど ちりぬるを わがよたれぞ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせず

縱 Latin

f:id:Kureduki_Maari:20181201234802j:plain
Quick brown fox jumps over the lazy dog.

ももんが

f:id:Kureduki_Maari:20181202000738j:plain

12/2

橫假名

f:id:Kureduki_Maari:20181203004632j:plain
とりなくこゑす ゆめさませ みよあけわたる ひんかしを そらいろはえて おきつへに ほふねむれゐぬ もやのうち

f:id:Kureduki_Maari:20181203004659j:plain
火星に榮光、地に平和、人には善意があります樣に。

縱 Latin

f:id:Kureduki_Maari:20181203190959j:plain
Rafael Alberti "El mar. La mar"

ももんが

f:id:Kureduki_Maari:20181207093511j:plain

12/3

橫假名

f:id:Kureduki_Maari:20181203004839j:plain
あめ つち ほし そら やま かは みね たに くも きり むろ こけ ひと いぬ うへ すゑ ゆわ さる おふせよ えのYEを なれゐて

f:id:Kureduki_Maari:20181203005108j:plain
火星帝國國歌。

縱 Latin

f:id:Kureduki_Maari:20181210203316j:plain
длина кириллицы (Dlina krillicy) (方式はISO 9:1995)

ももんが

f:id:Kureduki_Maari:20190111113457j:plain

12/4

橫假名

f:id:Kureduki_Maari:20181205112229j:plain
ゾンビランドサガのオープニングより。

縱 Latin

f:id:Kureduki_Maari:20181210204732j:plain
3.14159265359 , 2.71828182846

ももんが

f:id:Kureduki_Maari:20190111113510j:plain

12/5

橫假名

f:id:Kureduki_Maari:20181207095635j:plain
みんなも よこがなで いろいろな ことばを かいて みて くださいね。 かけたら ハッシュタグ “#橫假名” もしくは “#横仮名” を つけて とうかう 之てね。

縱 Latin

f:id:Kureduki_Maari:20181210231850j:plain
Robert Browning "Pippa's Song"

ももんが

12/6

橫假名

f:id:Kureduki_Maari:20181210235307j:plain
ねがはくは 花のもとにて 春死なむ その如月の 望月のころ (西行)

縱 Latin

f:id:Kureduki_Maari:20181210234100j:plain
I'm going to make him an offer he can't refuse.

ももんが

12/7

橫假名

f:id:Kureduki_Maari:20181215015958j:plain
のめやうたえ

縱 Latin

f:id:Kureduki_Maari:20181216002104j:plain
Bibe, cantabo. (のめやうたえ)

ももんが

12/8

橫假名

f:id:Kureduki_Maari:20181216002400j:plain
こえこえず心をかくるなみもなし人の思ひぞ末の松山 (藤原定家)

縱 Latin

f:id:Kureduki_Maari:20181230231939j:plain
Simple made easy

ももんが

12/9

橫假名

f:id:Kureduki_Maari:20181216002722j:plain
あけぬとていでつる人のあともなしただ時のまにつもる白雪 (藤原定家)

縱 Latin

f:id:Kureduki_Maari:20181230232215j:plain
x2 - n y2 = 1

ももんが

12/10

橫假名

f:id:Kureduki_Maari:20181210120029j:plain
すっごい にじむよ!

f:id:Kureduki_Maari:20181210120121j:plain
いっしゃう もじ かいて あそんで くらしたい!!!

f:id:Kureduki_Maari:20181210174053j:plain
もう直ぐ生誕日の人がゐるので。

縱 Latin

f:id:Kureduki_Maari:20181230232559j:plain
All's well that ends well.

ももんが

12/11

橫假名

f:id:Kureduki_Maari:20181216003046j:plain
おもひやる室の八島をそれと見ば聞くに煙のたちやまさらん (藤原定家)

縱 Latin

f:id:Kureduki_Maari:20181230233010j:plain
Curiosity killed the cat.

ももんが

12/12

橫假名

f:id:Kureduki_Maari:20181216004048j:plain
しぐれゆくよものこずゑの色よりも秋はゆふべのかはるなりけり (藤原定家)

縱 Latin

f:id:Kureduki_Maari:20181230233327j:plain
Please do not act like a baby.

ももんが

12/13

橫假名

f:id:Kureduki_Maari:20181229152630j:plain
ヨコガナ

縱 Latin

f:id:Kureduki_Maari:20181230233558j:plain
Bien está lo que bien acaba.

ももんが

12/14

橫假名

f:id:Kureduki_Maari:20181229152725j:plain
昔せし隠れ遊びになりなばや片すみもとによりふせりつつ (西行)

縱 Latin

f:id:Kureduki_Maari:20181230234028j:plain
A caballo regalado, no le mires el diente.

ももんが

12/15

橫假名

f:id:Kureduki_Maari:20181229152951j:plain
旅に病で夢は枯野をかけ廻る (芭蕉)

縱 Latin

f:id:Kureduki_Maari:20181230234538j:plain
Ayunen los santos, que no tiene tripa. Barriga llena, a Dios alaba.

ももんが

12/16

橫假名

f:id:Kureduki_Maari:20181216005243j:plain
石となれ 石は 怖れも 苦しみも 憤りも なけむ はや 石となれ

f:id:Kureduki_Maari:20181216010137j:plain
我はもや 石とならむず 石となりて 冷たき海を 沈み行かばや

f:id:Kureduki_Maari:20181217214530j:plain
氷雨 降り狐火 燃YEむ 冬の 夜に われ 石となる 黑き 小石に

f:id:Kureduki_Maari:20181217214619j:plain
眼 瞑づれば 氷の 上を 風が 吹く 我は 石となりて 轉びて行くを

縱 Latin

f:id:Kureduki_Maari:20181217214711j:plain
„An die Freude“ の一部。竊かに泣き乍ら此の集ひを立ち去って下さい。

ももんが

12/17

橫假名

f:id:Kureduki_Maari:20181229153127j:plain
ひらひらと挙ぐる扇や雲の峰 (芭蕉)

縱 Latin

f:id:Kureduki_Maari:20181230235243j:plain
Alter schützt vor Torkeit nicht.

ももんが

12/18

橫假名

f:id:Kureduki_Maari:20181229153218j:plain
詩がわたしたちの歌を捨てた時わたしたちの詩は死んだのです (麻井シキ)

縱 Latin

f:id:Kureduki_Maari:20181230235742j:plain
Zeit ist Geld.

ももんが

12/19

橫假名

f:id:Kureduki_Maari:20181229153603j:plain
月夜に拾って猫を飼う (麻井シキ)

縱 Latin

f:id:Kureduki_Maari:20181230235931j:plain
cogito, ergo sum.

ももんが

12/20

橫假名

f:id:Kureduki_Maari:20181229153719j:plain
私の心臓に鈴を結んで、跳び跳ねるとちりちり鳴ります (麻井シキ)

縱 Latin

f:id:Kureduki_Maari:20181231000258j:plain
vita brevis, ars longa.

ももんが

12/21

橫假名

f:id:Kureduki_Maari:20181222204410j:plain
なんだか とっても つかれて ゐて、げんじつの ぺんを にぎる きりょくが ない。

f:id:Kureduki_Maari:20181222204636j:plain
ざるで みづを くんでゐるやうな くうきょな とろうかんだけが ある。

縱 Latin

f:id:Kureduki_Maari:20181231000529j:plain
Mi amas vin.

ももんが

12/22

橫假名

f:id:Kureduki_Maari:20181229153926j:plain
切って配った私の体の籠いっぱいの部品が (麻井シキ)

縱 Latin

f:id:Kureduki_Maari:20181231000948j:plain
mi prami do .isemu'ibo dunda lo melbi xrula

ももんが

12/23

橫假名

f:id:Kureduki_Maari:20181223233011j:plain
ふゆ きたりなば はる とほからじ

f:id:Kureduki_Maari:20181223233202j:plain
文字の精靈は我等に安寧を與へ、また奪ふ。

縱 Latin

f:id:Kureduki_Maari:20181231001354j:plain
Allah bir kapiyi kaparsa bin kapiyi açar.

ももんが

12/24

橫假名

f:id:Kureduki_Maari:20181229154019j:plain
世界は深くわたしの既知である (麻井シキ)

縱 Latin

f:id:Kureduki_Maari:20181230231802j:plain
grass wWWwww (麻井シキ)

ももんが

12/25

橫假名

f:id:Kureduki_Maari:20181225221300j:plain
メリークリスマス

縱 Latin

f:id:Kureduki_Maari:20181225221315j:plain
2018-12-25 / Merry Christmas / Happy Holidays

ももんが