CentOS 8 をインストールしてみた

新しい PC を買ったんだ。これまで Dell か HP だったので、今回は Lenovo にしてみた。ThinkCentre M630e Tiny っていうモデル。てのひらにはちょっとあまるけど、超小型 PC と言っていい大きさだ。

で、せっかくなので最近リリースされたばかりの CentOS 8.0.1905 をインストールしてみた。プレインストールされていた Windows 10 は削除。

インストーラは CentOS 7 と特段変わらない印象。でもデフォルトのインストールタイプ(っていうんだっけ?)が、「サーバー(GUI使用)」になってた。もちろんこれでOK。ひととおりインストールが済んで再起動すると、ちゃんと CentOS が立ち上がった。いつかの Dell の PC みたいに起動しないなんてことはなかった。いい兆候だ。あと、ホスト名は rollo にした。

日本語入力

インストール時に日本語を選んでいるので、メニューとかは日本語になってるんだけど、そのままでは入力はできないようだ。↓このページが参考になった。

cf. デスクトップ環境 : GNOME デスクトップ インストール – Server World

まずは日本語入力プログラムをインストール。

[takatoh@rollo ~]$ sudo dnf -y install ibus-kkc

CentOS 7 までの yum コマンドじゃなくて dnf っていうコマンドでパッケージをインストールするらしい。

それから、背景画面の適当なところで右クリックして設定ウィンドウをひらいて、 Region & Language に移動する。入力ソースの欄で、日本語(かな漢字)を追加すれば準備は完了。画面右上のアイコンをクリックして日本語(かな漢字)を選べば OK だ。あとは半角/全角キーで入力モードを切り替えられる。今日のこのエントリもそうやって書いている。

Ruby とか Python とか

Python が入ってない、と思ったら python3 コマンドだった。

[takatoh@rollo ~]$ python3 -V
Python 3.6.8

Python はデフォルトが 3 系になったらしい。なら python コマンドでいいだろうになんで python3 なんだ。

Ruby は入ってない。のでインストールした。

[takatoh@rollo ~]$ ruby -v
bash: ruby: コマンドが見つかりませんでした…
コマンド ruby' を提供するためにパッケージ 'ruby' をインストールしますか? [N/y] y
キューで待機中… 
パッケージの一覧をロード中。… 
以下のパッケージはインストールされるべきものです:
ruby-2.5.3-104.module_el8.0.0+179+565e49e2.x86_64    An interpreter of object-oriented scripting language
ruby-irb-2.5.3-104.module_el8.0.0+179+565e49e2.noarch    The Interactive Ruby
ruby-libs-2.5.3-104.module_el8.0.0+179+565e49e2.x86_64    Libraries necessary to run Ruby
rubygem-bigdecimal-1.3.4-104.module_el8.0.0+179+565e49e2.x86_64    BigDecimal provides arbitrary-precision floating point decimal arithmetic
rubygem-did_you_mean-1.2.0-104.module_el8.0.0+179+565e49e2.noarch    "Did you mean?" experience in Ruby
rubygem-io-console-0.4.6-104.module_el8.0.0+179+565e49e2.x86_64    IO/Console is a simple console utilizing library
rubygem-json-2.1.0-104.module_el8.0.0+179+565e49e2.x86_64    This is a JSON implementation as a Ruby extension in C
rubygem-openssl-2.1.2-104.module_el8.0.0+179+565e49e2.x86_64    OpenSSL provides SSL, TLS and general purpose cryptography
rubygem-psych-3.0.2-104.module_el8.0.0+179+565e49e2.x86_64    A libyaml wrapper for Ruby
rubygem-rdoc-6.0.1-104.module_el8.0.0+179+565e49e2.noarch    A tool to generate HTML and command-line documentation for Ruby projects
rubygems-2.7.6-104.module_el8.0.0+179+565e49e2.noarch    The Ruby standard for packaging ruby libraries
変更したまま継続しますか? [N/y] y
キューで待機中… 
認証を待ち受け中… 
キューで待機中… 
パッケージをダウンロード中… 
データを要求中… 
変更をテスト中… 
パッケージのインストール中… 
ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux] 
[takatoh@rollo ~]$ ruby -v
ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux]

2.5.3 がインストールされた。

というところで、今日はここまで。

Visual Studio Community 2019

Visual Studio Community 2019 をインストールしてみた。

ダウンロードはここから、Community 版をダウンロードした。

 cf. https://visualstudio.microsoft.com/ja/downloads/

ダウンロードしたファイルは、必要なファイルをダウンロードしながらインストールするタイプのものだ。実行すると少したって、コンポーネント(っていうのか?)を選ぶ、ワークロードっていう画面になるので、今回は「.NETデスクトップ開発」を選んでみた。なんかダウンロードするファイルが1.2GBくらいあって、しばらく時間がかかる。

インストールが完了すると、Windows の再起動を促される。指示通り再起動。これで完了(たぶん)。

Windows の再起動後、スタートメニューから Visual Studio 2019 を選んで起動すると、最初はサインインの画面になった。[email protected] でサインインする。初期化かなんかが行われたあと、作業できるようになる。

「新しいプロジェクトの作成」を選んでみよう。とりあえず「コンソールアプリ」。プロジェクト名を入力して「作成」をクリック。すると、どうやらサンプルとして、いわゆる hello wold プログラムのコードが書かれている画面になる。これがプロジェクトの編集画面らしい。

というわけで、ひとまずは大丈夫のようだ。あと2カ月で年も変わるし、C# でもやってみるかな。

古いエントリが正常に表示されない

いつからかわからないけど、古いエントリが正常に表示されないようになっていた。も少し正確に言うと、古いエントリのうちの一部だ。さっき気が付いた。

で、調べてみると、どうも Crayon Syntax Hightlighter を使ってるエントリがダメみたいだ。コードをハイライトしてくれるプラグインだけど、今のバージョンの WordPress ではテストされてない、っていうか最近開発が止まっているようだ。それでも少し前まではとりあえず表示はできていたのに、たぶん WordPress のどこかのバージョンアップを境にダメになったんだろう。

Crayon Syntax Hightlighter は対応する言語も多くて重宝してたんだけど(いい代替プラグインはまだ見つかっていない)、エントリ自体が表示されないんじゃ、置き換えなきゃダメだろう。

うへぇ、かなりあるぞ。

画像をフェードアウト/フェードインで自動で切り替える

うわー!もう今月終わりそう!

というわけで、Scala の学習のほうはここひと月ほど滞っているんだけど、代わりに(?)今日は、HTML と JavaScript でタイトルに書いたようなことをやってみる。

jQuery を使ってスライドショーを実現するライブラリはいろいろあるんだけど、今日はそういうのは使わないでやる。さらには、jQuery 自体も使わないでやる。やるって言ったらやる。

さて、まずは jQuery 利用バージョン。いくつかの Web ページを参考に書いた(というかほぼコピペ)のがこれ。

<!DOCTYPE html>
<html>
  <head>
    <title>Fade images</title>
    <link rel="stylesheet" href="style.css" />
    <script src="../lib/jquery-3.4.1.min.js"></script>
    <script type="text/javascript">
      $(function() {
        const $width = 960;
        const $height = 540;
        const $interval = 3000;
        const $fade_speed = 1000;
        $("#slide ul li").css({"position": "absolute", "overflow": "hidden", "width": $width, "height": $height});
        $("#slide ul li").hide();
        $("#slide ul li:first").addClass("active").show();
        setInterval(function() {
          let $active = $("#slide ul li.active");
          let $next = $active.next("li").length ? $active.next("li") : $("#slide ul li:first");
          $active.fadeOut($fade_speed).removeClass("active");
          $next.fadeIn($fade_speed).addClass("active");
        }, $interval);
      });
    </script>
  </head>
  <body>
    <div id="slide">
      <ul>
        <li><a href=""><img src="img/img1.jpg" width="960" heght="540"/></a></li>
        <li><a href=""><img src="img/img2.jpg" width="960" heght="540"/></a></li>
        <li><a href=""><img src="img/img3.jpg" width="960" heght="540"/></a></li>
        <li><a href=""><img src="img/img4.jpg" width="960" heght="540"/></a></li>
      </ul>
    </div>
  </body>
</html>

これで、3秒ごとにフェードアウト/フェードインしながら画像が切り替わる。画像は4つ用意したけど、最後まで行ったら元に戻る。

つぎ。jQuery なしバージョン。さらにいくつかのページを参考に、試行錯誤した結果がこれ。

<!DOCTYPE html>
<html>
  <head>
    <title>Fade images</title>
    <link rel="stylesheet" href="style.css" />
    <script type="text/javascript">
      function fadeIn(el, speed) {
        el.style.transition = speed;
        el.style.opacity = "1";
      }

      function fadeOut(el, speed) {
        el.style.transition = speed;
        el.style.opacity = "0";
      }

      function slide() {
        const width = "960px";
        const height = "540px";
        const interval = 3000;  // miliseconds
        const fade_speed = "1.0s";
        const slide = document.querySelectorAll("#slide ul li");
        for (let i =0; i < slide.length; i++) {
          slide[i].style.position = "absolute";
          slide[i].style.overflow = "hidden";
          slide[i].style.width = width;
          slide[i].style.height = height;
          slide[i].style.display = "block";
          slide[i].style.opacity = "0";
        }
        const first = slide[0];
        first.classList.add("active");
        first.style.opacity = "1";
        setInterval(function() {
          let active = document.querySelector("#slide ul li.active");
          let next = active.nextElementSibling || first;
          fadeOut(active, fade_speed)
          active.classList.remove("active");
          fadeIn(next, fade_speed)
          next.classList.add("active");
        }, interval);
      }

      document.addEventListener("DOMContentLoaded", slide);
    </script>
  </head>
  <body>
    <div id="slide">
      <ul>
        <li><a href=""><img src="img/img1.jpg" width="960" heght="540"/></a></li>
        <li><a href=""><img src="img/img2.jpg" width="960" heght="540"/></a></li>
        <li><a href=""><img src="img/img3.jpg" width="960" heght="540"/></a></li>
        <li><a href=""><img src="img/img4.jpg" width="960" heght="540"/></a></li>
      </ul>
    </div>
  </body>
</html>

動作は同じ。

最近の流れとしては jQuery 使わないっていうのがあるみたいだけど、やっぱ使ったほうが楽ではあるよなあ。

2つの型クラスを使う

任意のリストの合計を計算する sum メソッドを作ったときには、「足すことのできる」型クラスとして Additive という型クラスと、そのインスタンス IntAdditive、StringAdditive を作った。

今回は、リストの平均を求める average メソッドを作ってみよう。Int に限れば次のように定義することができる。要素を合計して要素数で割っているだけだ。

scala> def average(lst: List[Int]): Int = lst.foldLeft(0)((x, y) => x + y) / lst.length
average: (lst: List[Int])Int

使い方も簡単。

scala> average(List(1, 3, 5))
res0: Int = 3

さて、この average メソッドを、Int でも Double でも使えるようにしたい。

合計を求めるのには Additive を使えばいいだろう。だけどそれだけじゃ足りない。1つには、要素数で割る必要があるので割り算もできなければならない。もう1つは、要素数を求める length メソッドは Int を返すので、これを合計の型(Int か Double)に合わせてやる必要がある。

そこで、Additive をもっと一般化して、四則演算とゼロを持つ Num という型クラスを考えよう。で、Int と Double にそれぞれ対応する IntNum と DoubleNum というインスタンスを作る。ファイルは Num.scala。

trait Num[A] {
    def plus(a: A, b: A): A
    def minus(a: A, b: A): A
    def multiply(a: A, b: A): A
    def divide(a: A, b: A): A
    def zero: A
}

object Num {
    implicit object IntNum extends Num[Int] {
        def plus(a: Int, b: Int): Int = a + b
        def minus(a: Int, b: Int): Int = a - b
        def multiply(a: Int, b: Int): Int = a * b
        def divide(a: Int, b: Int): Int = a / b
        def zero: Int = 0
    }
    implicit object DoubleNum extends Num[Double] {
        def plus(a: Double, b: Double): Double = a + b
        def minus(a: Double, b: Double): Double = a - b
        def multiply(a: Double, b: Double): Double = a * b
        def divide(a: Double, b: Double): Double = a / b
        def zero: Double = 0.0
    }
}

それから、Int から変換する FromInt という型クラスと、FromIntToInt、FromIntToDoubleというインスタンスを作る。ファイルは FromInt.scala。

trait FromInt[A] {
    def to(from: Int): A
}

object FromInt {
    implicit object FromIntToInt extends FromInt[Int] {
        def to(from: Int): Int = from
    }
    implicit object FromIntToDouble extends FromInt[Double] {
        def to(from: Int): Double = from
    }
}

sbt console を起動して2つのファイルを読み込めば、準備は完了。

average メソッドの定義は次のようになる。

scala> def average[A](lst: List[A])(implicit a: Num[A], b: FromInt[A]): A = {
     |     val length: Int = lst.length
     |     val sum: A = lst.foldLeft(a.zero)((x, y) => a.plus(x, y))
     |     a.divide(sum, b.to(length))
     | }
average: [A](lst: List[A])(implicit a: Num[A], implicit b: FromInt[A])A

ここで1つ勘違いをしていたのを白状しよう。「implicit キーワードは引数リストの先頭にしか付けられない」というので、てっきり先頭の引数だけが implicit になるのだと思っていた。実際には引数リスト全体が implicit になるんだね。というわけで、ここでは a と b が implicit parameter になっている。言い換えると Num と FromInt という2つの型クラスを使っている。

さあ、最後に試してみよう。

scala> average(List(1, 3, 5))
res0: Int = 3

scala> average(List(1.5, 2.5, 3.5))
res1: Double = 2.5

このとおり、Int にも Double にも対応した average メソッドができた。

Implicitの探索範囲

Implicit Conversion や Implicit Parameter が探索される範囲には、次のような範囲がある。

  • ローカルで定義されたもの
  • import で指定されたもの
  • スーパークラスで定義されたもの
  • コンパニオンオブジェクトで定義されたもの

ここでは、コンパニオンオブジェクトに Implicit を定義するパターンを見てみる。

新しく Rational (有理数)型を定義するとして、次のように定義する。ここでは Rational.scala ファイルに書いた。

trait Additive[A] {
    def plus(a: A, b: A): A
    def zero: A
}

case class Rational(num: Int, den: Int)

object Rational {
    implicit object RationaAdditive extends Additive[Rational] {
        def plus(a: Rational, b: Rational): Rational = {
            if (a == zero) {
                b
            } else if (b == zero) {
                a
            } else {
                Rational(a.num * b.den + b.num * a.den, a.den * b.den)
            }
        }
        def zero: Rational = Rational(0, 0)
    }
}

同じディレクトリで sbt console を起動すると自動的に読み込まれる。

で、sum メソッドを定義。なんでファイルに書かないかというと、クラスやトレイトに属さないメソッドはファイルには書けない(たぶん)から。

scala> def sum[A](lst: List[A])(implicit m: Additive[A]) = lst.foldLeft(m.zero)((x, y) => m.plus(x, y))
sum: [A](lst: List[A])(implicit m: Additive[A])A

さて、これで準備は完了。有理数の合計を求めてみる。

scala> sum(List(Rational(1, 2), Rational(1, 3)))
res0: Rational = Rational(5,6)

ちゃんと計算できた。

コンパニオンオブジェクトに Implicit を定義しておくのはわかりやすいかもしれないな。覚えておこう。

型クラス

前回のエントリで見たような Implicit Parameter の使い方を、「型クラス(を使った計算)」という。

これは Haskell から持ってきたもので、Haskell の用語では Additive を型クラス、StringAdditive や IntAdditive をそのインスタンスと呼ぶ。

と、ここまで研修資料の通りに書いたところで違和感を覚えた。型クラスとインスタンスは Haskell をやったことがあるので覚えている。Implicit Parameter の使い方というよりは、型パラメータを持った Additive と具体的な型について実装した StringAdditive や IntAdditive の使いかたを型クラスとインスタンスとよび、Implicit Parameter を使うと簡潔に書ける、といったほうが正解だろう(と思う)。

いずれにしても Scala において型クラスとインスタンスは重要な位置を占めているらしいので、次回からもう少し見ていく。

Implicit Parameter (2)

Implicit Parameter のもう1つの使い方。順を追ってみていく。

何らかのリストの合計を求めるメソッド sum を考える。ポイントは何のリストかわからない(あるいは何のリストでもいいように)、というところだ。

Scala は静的型付け言語なので単純にはいかない。ではどうするかというと、まず、「足し合わせることができる」型を考える。Additive としよう。

scala> trait Additive[A] {
     |     def plus(a: A, b: A): A
     |     def zero: A
     | }
defined trait Additive

Additive は型パラメータを持っていて、これが目的のリストに要素の型になる。また、実装はしていないがメソッドを2つ宣言している。

  • plus :2つの値を足し合わせる
  • zero :ゼロに相当する値を返す

だ。

次に、この型を継承して、具体的な型についてメソッドを実装する。String と Int について実装しよう。

scala> object StringAdditive extends Additive[String] {
     |     def plus(a: String, b: String): String = a + b
     |     def zero: String = ""
     | }
defined object StringAdditive

scala> object IntAdditive extends Additive[Int] {
     |     def plus(a: Int, b: Int): Int = a + b
     |     def zero: Int = 0
     | }
defined object IntAdditive

そして最後に sum メソッド。Additive を使って、足し合わせるように実装する。

scala> def sum[A](lst: List[A])(m: Additive[A]) = lst.foldLeft(m.zero)((x, y) => m.plus(x, y))
sum: [A](lst: List[A])(m: Additive[A])A

これで出来上がり。2つ目の引数リストで Additive を受け取るところがポイント。使い方はこうする。

scala> sum(List(1, 2, 3))(IntAdditive)
res0: Int = 6

scala> sum(List("abc", "def", "ghi"))(StringAdditive)
res1: String = abcdefghi

うまく「合計」を計算できた。

さて、ここからが本題。何のリストを合計するのかはリストを見ればわかるのだから、StringAdditive とか IntAdditive を明示的に渡さなくてもうまくやってほしい。Implicit Parameter を使うとそれができる。

次のように、StringAdditive を IntAdditive の定義の前と、sum メソッドの最後に引数リストの m の前に implicit キーワードをつける。

scala> trait Additive[A] {
     |     def plus(a: A, b: A): A
     |     def zero: A
     | }
defined trait Additive

scala> implicit object StringAdditive extends Additive[String] {
     |     def plus(a: String, b: String): String = a + b
     |     def zero: String = ""
     | }
defined object StringAdditive

scala> implicit object IntAdditive extends Additive[Int] {
     |     def plus(a: Int, b: Int): Int = a + b
     |     def zero: Int = 0
     | }
defined object IntAdditive

scala> def sum[A](lst: List[A])(implicit m: Additive[A]) = lst.foldLeft(m.zero)((x, y) => m.plus(x, y))
sum: [A](lst: List[A])(implicit m: Additive[A])A

これで StringAdditive や IntAdditive を明示的に渡さなくてもよくなる。

scala> sum(List(1, 2, 3))
res0: Int = 6

scala> sum(List("abc", "def", "ghi"))
res1: String = abcdefghi

このとおり。

Implicit Parameter

Implicit Parameter は暗黙の引数だ。2つの使い方があるようだけど、今日はその1つ、あちこちで共通に使われる引数を、いちいち明示的に渡すのを省略するための使い方を見ていこう。

参考にしている Dwango の研修資料では、データベースのコネクションの例が示されているけど、ここではもっと簡単な例を示す。

scala> def add(x: Int)(implicit y: Int): Int = x + y
add: (x: Int)(implicit y: Int)Int

scala> def sub(x: Int)(implicit y: Int): Int = x - y
sub: (x: Int)(implicit y: Int)Int

scala> def mul(x: Int)(implicit y: Int): Int = x * y
mul: (x: Int)(implicit y: Int)Int

Implicit Parameter を使うには、引数宣言に implicit キーワードをつけるだけだ。ただし、implicit キーワードをつけられるのは引数リストの最初に引数だけ、という制約があるので、通常は複数の引数リストを持つメソッドにして最後に Implicit Parameter を持ってくるようだ。

さて、これらのメソッドを呼び出すと、Scala は現在のスコープで直近にある implicit とマークされた変数の値を、Implicit Parameter としてメソッドに引き渡す。具体的には次のようにする。

scala> implicit val z: Int = 2
z: Int = 2

scala> add(3)
res0: Int = 5

scala> sub(3)
res1: Int = 1

scala> mul(3)
res2: Int = 6

implicit val で宣言された変数 z が、メソッド呼び出しの時に暗黙に引き渡されている。

ここで、新しい変数を implicit で宣言したらどうなるだろう。

scala> implicit val z1: Int = 5
z1: Int = 5

scala> add(3)
<console>:15: error: ambiguous implicit values:
 both value z of type => Int
 and value z1 of type => Int
 match expected type Int
       add(3)
          ^

おや、エラーになった。どうやら、期待する Implicit Parameter にマッチする値が2つあるせいのようだ。こういう使い方はできないらしい。

明示的に渡してやったらどうだろう。

scala> add(3)(z1)
res4: Int = 8

ああ、これは普通にいけるのね。

というかさあ、こういうあちこちで使いまわす変数っていうのは、オブジェクト指向的にはオブジェクトのメンバー変数にしておくんだろうけど、Scala では違うんだろうか。

sudoku-solver

あいだが空いてしまった。ちょうど1週間だ。5月の連休中から Scala のエントリを1月以上も連続で更新してたのに。まぁ、別にいいんだけど。

で、今日から再開ということで Scala をやろうと思ったんだけど、事情があって Haskell だ。

数独っていうパズルがある。ナンプレともいう、マス目に 1 から 9 の数字を入れていくアレだ。暇つぶしにやってたんだけど、入門編の問題くらいはともかく、それ以上になると途端に難しくなる。向いてないのかもしれない。

ともかく、こんなのやってられねーってわけで、問題を解くプログラムを作ってみた。Haskell で。

作ったものは GitHub にあげたので見てほしい。

 cf. takatoh / sudoku-solver

使い方はこんな感じ。

^o^ > type example2.txt
     87
928    15
     1
14    8
   485
  6    43
   5
51    924
  92

^o^ > sudoku example2.txt
431658792
928734615
675921438
147362859
392485167
856197243
284519376
513876924
769243581

問題は 9 × 9 マスに入っている数字を 9 文字 × 9 行のテキストファイルにして、sudoku プログラムにファイル名を渡してやるだけ。

「数独 難問」でググって出てきた問題でもあっという間に解ける。ああ、気持ちいい。