Tambourine作業メモ

主にスキル習得のためにやった作業のメモ。他人には基本的に無用のものです。

GitLabのインストールをやってみる

ちょっと事情があって、ローカルのマシンにGitLabを入れる必要が出来た。練習にAWSのEC2にインストールしてみることにする。

まだ、OSに何を使うかは決まってないんだけども、とりあえずGitLabのインストールページの一番上にubuntuがあるので、これでやってみることにする。

ここを見ながらやる

Download and install GitLab | GitLab

EC2にt2.mediumのマシンを作って、

sudo apt-get update
sudo apt-get install -y curl openssh-server ca-certificates tzdata perl

を実行する。その後のpostfixのインストールはスキップする。

次に

curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh | sudo bash

を実行する。

インストーラーを起動するが、そこに外部からみたURLを与える必要があるらしい。お試しなので全然考えてないが、とりあえず、httpで、かつホスト名だけでアクセスしてみたい。どうせ今はSSH越しにしかアクセスしないだろうし。

とりあえず、ホスト名は変えておこう

sudo vi /etc/hosts
sudo hostnamectl set-hostname gitlabstudy

再起動して、インストーラーを起動してみる。ここで気付く。あれ?これってEnterprise Editionじゃん。Community Editionでいいんだけど・・・。ところが、別にお金を払いたくないという理由でCEを選ぶのなら、EEを入れてお金を払わないで使っていればいいらしい。「オレのマシンにプロプライエタリなコードは一切入って欲しくない!」という人は、CEを入れる事もできるらしい。なるほどね。

Community EditionとEnterprise Editionの違い | GitLab.JP

https://www.gitlab.jp/install/ce-or-ee/

sudo EXTERNAL_URL="http://gitlabstudy" apt-get install gitlab-ee

しかし、これはここを最後に固まってしまう

  * ruby_block[authorize Grafana with GitLab] action run

ググってみるとこんなのがみつかる

Ruby_block[authorize Grafana with GitLab] action run timeouts - Observability - GitLab Forum

最後のコメントに「メモリが足りないとなるんだよね」と書かれている。にわかに信じがたい。試しに、t2.large(メモリ8GB)で試してみると上手くいった。なんと・・・

Notes:
Default admin account has been configured with following details:
Username: root
Password: You didn't opt-in to print initial root password to STDOUT.
Password stored to /etc/gitlab/initial_root_password. This file will be cleaned up in first reconfigure run after 24 hours.

NOTE: Because these credentials might be present in your log files in plain text, it is highly recommended to reset the password following https://docs.gitlab.com/ee/security/reset_user_password.html#reset-your-root-password.

gitlab Reconfigured!

       *.                  *.
      ***                 ***
     *****               *****
    .******             *******
    ********            ********
   ,,,,,,,,,***********,,,,,,,,,
  ,,,,,,,,,,,*********,,,,,,,,,,,
  .,,,,,,,,,,,*******,,,,,,,,,,,,
      ,,,,,,,,,*****,,,,,,,,,.
         ,,,,,,,****,,,,,,
            .,,,***,,,,
                ,*,.
  


     _______ __  __          __
    / ____(_) /_/ /   ____ _/ /_
   / / __/ / __/ /   / __ `/ __ \
  / /_/ / / /_/ /___/ /_/ / /_/ /
  \____/_/\__/_____/\__,_/_.___/
  

Thank you for installing GitLab!
GitLab should be available at http://gitlabstudy

For a comprehensive list of configuration options please see the Omnibus GitLab readme
https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md

Help us improve the installation experience, let us know how we did with a 1 minute survey:
https://gitlab.fra1.qualtrics.com/jfe/form/SV_6kVqZANThUQ1bZb?installation=omnibus&release=14-9

パスワード書いたファイルは24時間で消えると書かれてる。怖い

ubuntu@gitlabstudy:/etc/gitlab$ sudo cat initial_root_password 
# WARNING: This value is valid only in the following conditions
#          1. If provided manually (either via `GITLAB_ROOT_PASSWORD` environment variable or via `gitlab_rails['initial_root_password']` setting in `gitlab.rb`, it was provided before database was seeded for the first time (usually, the first reconfigure run).
#          2. Password hasn't been changed manually, either via UI or via command line.
#
#          If the password shown here doesn't work, you must reset the admin password following https://docs.gitlab.com/ee/security/reset_user_password.html#reset-your-root-password.

Password: 8f70FrnDhG1OOIjmHNjmrZ+anZGCAed7ExhD3Hfvfo8=

# NOTE: This file will be automatically deleted in the first reconfigure run after 24 hours.

自分の/private/etc/hostsにgitlabstudyの行を作って

ssh -L 8080:localhost:80 gitlabstudy

した上で、http://localhsot:8080/にアクセスするとGitLabの画面にアクセス出来る。

「Pythonではじめる機械学習」を読んでみる(2)

前回、いろいろなライブラリをインストールしたりしたんだけども、著者お手製のmglearnっていうのをインストールしてねというところでちょっと面倒くさいなーという気持ちになった。そこで、この本のGitHubページをcloneして、そこのnotebookを使うことにした。自分でやった感が一気になくなるので気持ちはそそらないんだけども、まあ、とりあえずね。

で、そのnotebookである 01-introduction.ipynb を走らせたら、1行目でエラーになるという。まあ、あるあるである。

from preamble import *
%matplotlib inline
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Input In [1], in <cell line: 1>()
----> 1 from preamble import *
      2 get_ipython().run_line_magic('matplotlib', 'inline')

File ~/study/introduction_to_ml_with_python/preamble.py:5, in <module>
      3 import numpy as np
      4 import matplotlib.pyplot as plt
----> 5 import mglearn
      6 from cycler import cycler
      8 set_matplotlib_formats('pdf', 'png')

File ~/study/introduction_to_ml_with_python/mglearn/__init__.py:1, in <module>
----> 1 from . import plots
      2 from . import tools
      3 from .plots import cm3, cm2

File ~/study/introduction_to_ml_with_python/mglearn/plots.py:2, in <module>
      1 from .plot_linear_svc_regularization import plot_linear_svc_regularization
----> 2 from .plot_interactive_tree import plot_tree_progressive, plot_tree_partition
      3 from .plot_animal_tree import plot_animal_tree
      4 from .plot_rbf_svm_parameters import plot_svm

File ~/study/introduction_to_ml_with_python/mglearn/plot_interactive_tree.py:8, in <module>
      6 from io import StringIO
      7 from sklearn.tree import export_graphviz
----> 8 from imageio import imread
      9 from scipy import ndimage
     10 from sklearn.datasets import make_moons

ModuleNotFoundError: No module named 'imageio'

imageioがないってさ。インストールしてみるかね。

> pip3 install -U imageio
DEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621
Collecting imageio
  Downloading imageio-2.16.2-py3-none-any.whl (3.3 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.3/3.3 MB 14.0 MB/s eta 0:00:00
Requirement already satisfied: numpy>=1.20.0 in /usr/local/lib/python3.9/site-packages (from imageio) (1.22.3)
Requirement already satisfied: pillow>=8.3.2 in /usr/local/lib/python3.9/site-packages (from imageio) (9.1.0)
Installing collected packages: imageio
  DEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621
DEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621
Successfully installed imageio-2.16.2

入った。もう一度やってみよう。

from preamble import *
%matplotlib inline
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [2], in <cell line: 1>()
----> 1 from preamble import *
      2 get_ipython().run_line_magic('matplotlib', 'inline')

File ~/study/introduction_to_ml_with_python/preamble.py:16, in <module>
     13 plt.rcParams['lines.linewidth'] = 2
     14 plt.rcParams['legend.numpoints'] = 1
     15 plt.rc('axes', prop_cycle=(
---> 16     cycler('color', mglearn.plot_helpers.cm_cycle.colors) +
     17     cycler('linestyle', ['-', '-', "--", (0, (3, 3)), (0, (1.5, 1.5))])))
     19 np.set_printoptions(precision=3, suppress=True)
     21 pd.set_option("display.max_columns", 8)

AttributeError: module 'mglearn' has no attribute 'plot_helpers'

なんでほわーい。mglearn/prot_helpers.pyはちゃんとあるし。

preamble.pyや、mglearn/__init__.pyを見てみたりしてみたけど、わからん・・・。

ところが、preamble.pyimportコメントアウトして、エラーメッセージが変わることなんかを確認したりして、なんどかnotebookも再起動させたりしているウチに、動くようになった。

どゆこと?

preamble.pyを書き換えて、import直後にprint(dir(mglearn)) してみたら、確かにplot_helpersいるし

['ReBl', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'cm2', 'cm3', 'datasets', 'discrete_scatter', 'plot_2d_separator', 'plot_agglomerative', 'plot_animal_tree', 'plot_cross_validation', 'plot_dbscan', 'plot_decomposition', 'plot_grid_search', 'plot_helpers', 'plot_improper_preprocessing', 'plot_interactive_tree', 'plot_kmeans', 'plot_knn_classification', 'plot_knn_regression', 'plot_linear_regression', 'plot_linear_svc_regularization', 'plot_metrics', 'plot_nmf', 'plot_nn_graphs', 'plot_pca', 'plot_rbf_svm_parameters', 'plot_ridge', 'plot_scaling', 'plot_tree_nonmonotonous', 'plots', 'tools']

ホント、そういうとこやぞ!

というわけで、Pythonのモジュールの仕組みはさっぱりわからない。だけど、この1章のnotebookはエラーなく実行されたみたい。

さて、一緒に勉強会をやっているメンバーでもmglearnのインストール忘れでエラーになる人はちょいちょいいる。そりゃそうだろうし、なんか入れるのやだなと後回しにしているとひっかかる。

図の1.3でグラフを書いているんだけども、そこでmglearnがパラメータに使われていて、ある人が「抜いても別にプロットはされます」と言っている。ふむ。

これが、cloneしたnotebookそのままでプロットしたグラフ

f:id:Tambourine:20220413172254p:plain

こっちが、cmap=mglearn.cm3を抜いたもの

f:id:Tambourine:20220413172418p:plain

cmapはcolor mapなのかな。探してみる

mglearn/plot_helpers.py

cm3 = ListedColormap(['#0000aa', '#ff2020', '#50ff50'])

ってのがある。これだけだね。

というわけで、本はなにひとつ読み進んでないんだけども、今日のところはここまで。

「Pythonではじめる機械学習」を読んでみる(1)

この本を読んでみようという勉強会にやじうま参加中。途中で挫折予定。この本はhttps://learning.oreilly.comで日本語が読めるのでありがたい

まずは1章

scikit-learnをインストールしろと書いてある。condaで入れとけばいいんじゃね?と書いてあるんだけど、自分のマシンにはcondaはなくて、でもjupyter notebookはある。うーむ・・・どういう状況か覚えてない。

とりあえず、scikit-learn.orgのインストールガイドに従ってpipで入れてみる。

> pip3 install -U scikit-learn
DEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621
Collecting scikit-learn
  Downloading scikit_learn-1.0.2-cp39-cp39-macosx_10_13_x86_64.whl (8.0 MB)
     |████████████████████████████████| 8.0 MB 5.2 MB/s            
Collecting scipy>=1.1.0
  Downloading scipy-1.8.0-cp39-cp39-macosx_12_0_universal2.macosx_10_9_x86_64.whl (55.6 MB)
     |████████████████████████████████| 55.6 MB 418 kB/s            
Collecting threadpoolctl>=2.0.0
  Downloading threadpoolctl-3.1.0-py3-none-any.whl (14 kB)
Collecting numpy>=1.14.6
  Downloading numpy-1.22.3-cp39-cp39-macosx_10_14_x86_64.whl (17.6 MB)
     |████████████████████████████████| 17.6 MB 33.2 MB/s            
Collecting joblib>=0.11
  Downloading joblib-1.1.0-py2.py3-none-any.whl (306 kB)
     |████████████████████████████████| 306 kB 6.7 MB/s            
Installing collected packages: numpy, threadpoolctl, scipy, joblib, scikit-learn
  DEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621
  DEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621
  DEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621
  DEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621
  DEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621
DEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621
Successfully installed joblib-1.1.0 numpy-1.22.3 scikit-learn-1.0.2 scipy-1.8.0 threadpoolctl-3.1.0
WARNING: You are using pip version 21.3.1; however, version 22.0.4 is available.
You should consider upgrading via the '/usr/local/opt/python@3.9/bin/python3.9 -m pip install --upgrade pip' command.

なんかめっちゃDEPRECATION出てきて気になるが、いったん置いておく。

1.6節で必要なライブラリが指定されている。pandas入ってなかった(笑)。ちまちまpipで入れる。

f:id:Tambourine:20220406164224p:plain
ライブラリのバージョン

結果、こんな感じ。

様々なものを使っていて、それぞれリンクが示されているので、ここにまとめとく

この後、サンプルデータで一回ししてみるところへ続いていくのだけど、今日はセットアップで力尽きた

F#で遊んでみる(11)

8.15のアクティブパターンから

これまでのパターンマッチングでレコードやタプルにマッチさせるパターンが存在したけど、自分で定義したクラスにはあらかじめ定義されたパターンは存在しない。なので自分で定義する。これをアクティブパターンという。

アクティブパターンとは

  • 関数である
  • (| ... |)の形でパターンを定義する。バナナクリップと呼ぶらしい
  • 引数がパターンマッチさせる対象の値で、引数の型に対して、網羅的なパターンである
  • マッチしたパターンごとに値を返すことが出来る
  • Choice型を返す
  • バナナクリップ付きで関数として実行可能
  • マッチに失敗するパターンは(|パターン|_|)と記述する。この場合、optionを返す

面白い。

8.16は、構造体。構造体は、スタックに確保されるユーザー定義型のこと。クラスと同じ構文だけど、属性としてStructを指定する。まあ、使うことは普通はないよね。

その次、8.17はデリゲートについて。ここは例えばGroovyとJavaと同じように、F#のラムダ式C#のデリゲートに変換するような仕組みがある。C#との互換のためにF#にもデリゲートを定義する構文はあるけど、使わないと思うので割愛。

8.18に列挙型。F#には判別共用体があるけど、それと別にC#Enumを扱うための構文がある・・・がなんでもtypeなんでこれがC#にいくとEnumになるというのは見てわかる自信がない。まあ、割愛。

8.19は型拡張。これも今は割愛。名前からしC#のExtensionかと思ったら互換性ないらしい。あらら。

8.20は演算子オーバーロード。うーん、まあF#側でわざわざこれはやらないかな。というか、この辺は欲しくなったらC#で書いて組み合わせて使えば良い気がする。

8.21はジェネリック制約。以下が出てくるけど、こういうものがあるということだけ覚えておいて、これを使う必要があるものを作っちゃったら読み直そう。

  • フレキシブル型
  • コンストラクター制約
  • null制約
  • 値型制約、参照型制約
  • 列挙型制約、デリゲート制約
  • 明示的メンバー制約(inlineがついてないとダメ)

このへんが適切に設計されているのかどうかは、型理論に明るくないのでさっぱりわからない。まあ、いいか。

F#で遊んでみる(10)

この本を読んでます。

8章。OOP。F#はOOPも出来ます・・・というよりは、C#が使うことを前提に設計された実行基板の上で動くので、C#と同じ事はどうやったら出来るのかという話。

まず、今までのレコードについて。

  • レコード(typeで定義するやつ)にはmemberが定義出来る。関数を入れても値を入れてもいい(JSみたいな感じかな)
    • memberで引数を持つ関数を定義すると、メソッドになる。インスタンスメソッドの自分自身を表す仮引数(C#のthis)はメソッド名の前にx.methodNameの形式で書くのが特徴
    • memberで引数を持たない関数を定義すると、プロパティになる
    • static memberを使うとクラスメソッドも定義出来る
    • overrideを使うとメソッドのオーバーライドが出来る。単にmemberを使うと親クラスのメソッドを隠蔽するよというwarningが出る
    • 明示しなければ、暗黙でSystem.Objectを継承する

レコードは特別扱いされて内部的にクラスになるが、クラスを定義することもできる。

  • クラスはtypeでプライマリコンストラクタを記述することにより定義する
    • インスタンスの初期化はletを使う
    • static letを使うと型の初期化が行われる
    • ゲッターやセッターも定義出来る
    • コンストラクタは複数定義出来る(ので、typeを使って定義するものをプライマリと呼ぶ)
    • メソッド、プロパティ以外にフィールドというものもある・・・がよくわからない
    • Abstractなクラスも定義できる

この辺りは、C#で使うものをF#で作る時には大事そう・・・だけど、今の段階では適当に理解しておくことにする。

さらにメソッドについての追加の事項

  • メソッドとコンストラクタは名前付き引数が使える。仮引数の変数名を使う
  • メソッドとコンストラクタはオプショナル引数が使える。仮引数に?をつける。つけるとoptionになる。
    • 仮引数のデフォルト値を定義するためのdefaultArg関数がある。単に第1引数がNoneなら第2引数を返す
  • メソッドはオーバーロード出来る

後は、クラスのキャストに関する話、インターフェースの定義の話、無名クラスを作るためのオブジェクト式の話があるが割愛。

さらに、nullの話がある。F#にnullはないが、互換性の観点で入ってしまうことはあり得る。無理矢理入れるためのUnchecked.defaultof<'T>という関数もある。

8.15のアクティブパターンはちょっと面倒くさそうな話なので、次回

F#で遊んでみる(9)

7章のつづき。

まずは配列。配列はサイズ固定でミュータブル。要するに、メモリ上にべたっと領域があるってことですね。

  • 配列式。[| 1; 2; 3 |]
  • Array.zeroで配列の確保と初期化が出来る。ゼロで初期化したければzeroCreateを使う
  • 多次元配列はインデックスの開始を0じゃなく出来る
    • Array2D.zeroCreateBasedを使う
    • なんのためにそんなことをするんだろう?

そして、シーケンス。シーケンスは同じ型の値の列で、Consリスト(List)かメモリマップ(Array)かは気にしない抽象化概念。 で、実態としては(Pythonと同じ意味で)ジェネレーターになっている。つまり取り出すまで実際にメモリ上に値はないし、遅延評価される。

Seqライブラリにどんな関数があるかは・・・まあ、Listでみたのと変わらない。

  • List, Array, Seqモジュールはopen出来ない。RequireQualifiedAccess属性が付いているため。なので必ずList.mapのように使う
    • mapが呼ばれたとして、それがList.mapなのかArray.mapなのかSeq.mapなのか見分けるのは困難だからというのが理由

あと、古い.NET Frameworkのコレクションがseq<'T>互換じゃないってエラーが出る場合、 Seq.cast<'t>すればいい・・・と書いてあって、例としてMatchCollectionが例に挙げられているんだけど、これは直っちゃったっぽい

> open System.Text.RegularExpressions;;
> let re = Regex("\d+");;
val re: Regex = \d+

> let m = re.Matches("R171 R176 R1 R2");;
val m: MatchCollection

> m |> Seq.map (fun m -> m.Value);; // 本だとここがエラーになる
val it: seq<string> = seq ["171"; "176"; "1"; "2"]
  • Seq.unfold
    • foldの逆でシーケンスを生成する。生成の為の関数は'a -> ('b * 'a) option型になる。('b * 'a)の'bが要素になって、次の要素が'aを引数に続けて作られる。
  • Seq.cache
    • Lazy<'T>のようなキャッシュ機能をseq<'T>に後付けする
  • SeqはListやArrayと違って構造的な型ではなく、参照型。なので=で比較すると同値ではなく同一かがチェックされる
    • 等値性をチェックしたければcompareWithを使う。

次はSet。Setは常に整列済み、重複なしのイミュータブルな要素を持つ。つまり集合。実装としては二分木になってる。 Setモジュールの関数はこんな感じ

  • union(和)
  • difference(差)
  • intersect(積)
  • isSubset, isSuperset, isProperSubset(真部分集合), isProperSuperset
  • add, remove
  • .NET FrameworkにもHashSet, SortedSetがあるけど、こいつらはイミュータブル

最後はMap。2要素のタプルのリストからmap関数で生成出来る。Mapモジュールはこんな感じ。

  • find, tryFind
  • containsKey
  • findKey( 型が('a -> 'b -> bool) -> Map<'a,'b> -> 'a。つまり、k,vが渡ってきて、それを使ったチェックに通った要素が返ってくる)

F#で遊んでみる(8)

7章を読んでいこう。コレクションの話。

まずはリスト。関数型でリストといえば、(car, cdr)のリストだ。

  • 'a list
    • ::がcons。[]が空リスト
    • carはList.head。cdrはList.tail
    • パターンマッチ
      • 空リストパターン
      • コンスパターン(_::_みたいな感じ)
      • リストパターン([ _; x;]みたいな感じ)

リストは、記号をケース識別子にできているという点でコンパイラに特別扱いをされているけど、そこを普通のケース識別子を使っていいのであれば、DUとして定義出来るのが面白い。

> type MyList<'T> = 
-     |Nil
-     |Cons of 'T * MyList<'T>
- ;;
type MyList<'T> =
  | Nil
  | Cons of 'T * MyList<'T>

> let list = Cons (3, Cons(2, Cons(1, Nil)));;
val list: MyList<int> = Cons (3, Cons (2, Cons (1, Nil)))

再帰定義。一気にLISPっぽい。

さて、リストを扱うにはF#のListモジュールを使う。 たとえば、ソートはList.sortを使う。

この関数の型は、こうなってる。

> List.sort;;
val it: ('a list -> 'a list) when 'a: comparison

「comparison制約が付いている」と、読む。どういうことかは下を読む。

List (FSharp.Core)

Sorts the given list using Operators.compare.

というわけで、Operators.compare(Ruby出言うところのUFO演算子<=>にあたるもの)が定義されてないとダメだよってことですな。

で、sortはcompareを使って比較するわけだけども、比較する方法を与えてやりたいことはもちろんある。2つあって、

> List.sortBy;;
val it: (('a -> 'b) -> 'a list -> 'a list) when 'b: comparison

> List.sortWith;;
val it: (('a -> 'a -> int) -> 'a list -> 'a list)

この2つ。まあ、なんとなく想像は付きますな。sortByは'aから'bに変換する関数を渡して、'bを評価して並び替える。だから'bにcomparison制約が付く。sortWithの方は、今回限りのcompare関数を渡してソートする。

> let gengo = [("Meiji", 1868); ("Taisho", 1912); ("Showa", 1926); ("Heisei", 1989); ("Reiwa", 2019)];;
val gengo: (string * int) list =
  [("Meiji", 1868); ("Taisho", 1912); ("Showa", 1926); ("Heisei", 1989);
   ("Reiwa", 2019)]

> gengo |> List.sort;;     // タプルの比較は先頭の要素の比較
val it: (string * int) list =
  [("Heisei", 1989); ("Meiji", 1868); ("Reiwa", 2019); ("Showa", 1926);
   ("Taisho", 1912)]

> gengo |> List.sortBy (fun x -> match x with _, year -> - year);;  // タプルの2つ目の要素の逆順で比較
val it: (string * int) list =
  [("Reiwa", 2019); ("Heisei", 1989); ("Showa", 1926); ("Taisho", 1912);
   ("Meiji", 1868)]

> gengo |> List.sortWith (fun x y ->    // タプルの比較の逆順で比較
-     let i = compare x y
-     -i);;
val it: (string * int) list =
  [("Taisho", 1912); ("Showa", 1926); ("Reiwa", 2019); ("Meiji", 1868);
   ("Heisei", 1989)]

他にいろんな関数が紹介される

  • List.permute indexMap list
    • indexMap : int -> int // n番目の要素をm番目に移すっていうマップを示す関数
  • List.append

リストは内包表記もある。シーケンス式って言うらしい。見た目は、Pythonのアレとほぼ同じだね

> [1..3];;
val it: int list = [1; 2; 3]

> [0..2..10];;
val it: int list = [0; 2; 4; 6; 8; 10]

> [ for n in 0..9 do
-     let m = n * n
-     if m > 10 then m ]  
- ;;
val it: int list = [16; 25; 36; 49; 64; 81]

さて、ここで本では

> [ for n in 0..9 do
-     let m = n * n
-     if m > 10 then yield m ]  
- ;;

と書いてある。yieldを使うことによって、どれをリストの要素として返すのか明確にできる・・・のかな。ま、この例では省略可能です。

yieldには後ろに!が付いたバージョンもあって、yield!はflattenしてくれます。

> [ yield [1..3]
-   yield [4..6]
- ];;
val it: int list list = [[1; 2; 3]; [4; 5; 6]]

> [ yield! [1..3]
-   yield! [4..6]
- ];;
val it: int list = [1; 2; 3; 4; 5; 6]

他のListの関数がざっと紹介されている。

  • length
  • isEmpty
  • rev
    • reverseの略。何故略した・・・
  • nth

まあ、わかる。下は演算系

  • max
  • min
  • sum
    • sumBy
  • average
    • averageBy

これが実行出来るためにはsortの時と同じようにいろいろ条件が付く。比較できないとダメだったり、足し算が定義されてないとだめだったり。例えば、averageは割り算をした結果が同じ型にならないので、整数では使えない。小うるさいね。そのために、要素をfloatに変換する関数を引数に取れるaverageByが用意されてる。それはやり過ぎじゃない?(笑)

  • map
    • mapi(Rubyでいうところのmap.with_index)
    • map2(Rubyでいうところのzipしてmap)
  • reduce
  • fold
    • 初期値を指定するバージョンのreduce
  • foldBack, reduceBack
    • 後ろから適用する
  • zip
  • unzip
  • concat
  • collect(Rubyでいうところのflat_map/collect_concat)
  • filter
  • partition(渡した関数の結果がtrueとfalseの両方のバージョンを返すfilter)
  • choose(mapしてfilterする。mapするときはoptionを作るようにすると、filterがSomeだけにしてくれる。便利そう)
  • find(見つからなかったら例外)
  • tryFind(optionを返す)
  • findIndex/tryFindIndex
  • pick/tryPick(findしてmapする)
  • exists/forall(Rubyのany?とall?)
  • scan(foldの途中の計算結果をリストにして返す)
  • iter
  • toArray/ofArray, toSeq/ofSeq
    • 両方あるのが面白い

本でListモジュールで紹介されている関数は以上。

で、公式ドキュメントも見ておこう。10年の間に増えてるかもしれないし。

fsharp.github.io

  • allPairs(RubyのArray.product)
  • chunkBySize
  • compareWith(2つのリストを与えたcompare関数(List<'T> -> List<'T> -> int)で比較する)
  • contains
  • countBy(関数を渡して変換して、変換結果をtallyする)
  • distinct/distinctBy
  • exactlyOne(要素が一個だけならそれを取り出して返す。要素が空、もしくは複数なら例外)
  • expect(引数に渡したシーケンスに含まれているモノを対象から除外したリストを返す)
  • groupBy
  • indexed
  • insertAt
  • insertManyAt
  • item
  • pairwise(リストの先頭から2要素ずつ取ってペアを作る [1; 2; 3; 4] -> [(1, 2); (2, 3); (3,4)])
  • removeAt
  • removeManyAt
  • replicate(List.repl.icate 3 "a" -> ["a"; "a"; "a"])
  • singleton(引数をそれが1つだけ入ったリストにする)
  • skip(先頭のいくつかを飛ばす)
  • skipWhile
  • splitAt
  • splitInto(リストを指定した数に分割する)
  • transpose(転置行列を作る)
  • where(filterと同じ)
  • windowed

たっぷりあるね