ことり、穂乃果と一緒に学ぶHaskell(入門)その1「代数的データ型の定義」

前置き(海未ちゃん)

海未「この度は『ことり、穂乃果と一緒に学ぶHaskell(入門)』にお越しいただき、ありがとうございます」
海未「本企画はこちらの偉大なブログ様に触発されたものです。 是非こちらもご覧ください」

海未「キャラ崩壊を含む可能性があります。 ご容赦くださいますよう」
海未「それでは、よろしくお願いします 」



ことり、穂乃果と一緒に学ぶHaskell(入門)その1「代数的データ型の定義」

ーー ライブ練習終わり着替え後(部室) ーー

ことり「ふう〜、練習つかれたぁ」
ことり「ん……?」

ドタドタドタ

穂乃果「ことりちゃん〜〜、たすけてー!!」
ことり「わっ、ホノカチャン!! ど、どうしたの〜〜?」
穂乃果「この前、選択授業を選んだじゃん? 私はHaskellを選んで、1回目の授業を受けたんだけど、全然わからなくって……」


  • 音ノ木坂 2年時の選択科目
    1. Haskell
    2. Rust
    3. C++

穂乃果「前にJavaは習ったんだけど、HaskellってJavaとは全然違うみたいで、頭が追いつかなくて」
ことり「音ノ木坂は、必修の授業でJavaをやるもんね! うーん」

穂乃果「ことりちゃんって、たしかHaskell……やってたよね! だから教えて欲しくって。 ダメ……?」ウルウル

ことり(ううっ、穂乃果ちゃんにそんな顔されたら……ことりだって断れないよぅ)

ことり「わ、わかったよ! 大丈夫だよ、わたしにまかせて☆」
穂乃果「わぁ、ありがとうことりちゃん〜!」

ことり「穂乃果ちゃん、PCって今、持ってる?」
穂乃果「もちろん! 音ノ木坂の生徒はみんな学校から、ノートPCを貸し受けてるからね! よいしょっと」

ことり「うんうん。 じゃあちょっと見せてね。 ……よし、OSはArchLinux。 stackとテキストエディタは入ってるみたいだね」


  • この記事で使用する環境 及び 前提、既知とする環境
    • stack
    • なんらかのテキストエディタ
    • コマンドライン
    • stackの実行方法
      • 基本的にstack runghc -- {ファイル名}
    • Javaの基本知識
      • 構文を知っている程度を仮定します

ことり「じゃあ、やっていこうか☆」
穂乃果「よーし、私! ファイトだよっ!」

代数的データ型の定義

穂乃果「この前は『代数的データ型』っていうのについて習ったんだけど……今日はここを教えて欲しいなあ」
ことり「代数的データ型はHaskellの最もたる優れた要素だね!」

ことり「じゃあ、まずは代数的データ型の定義方法について説明するね」
ことり「穂乃果ちゃん、Javaでclassってあったよね。 こんな感じのclassをJavaで書いてみてくれる?」

  1. クラス名: Member
  2. コンストラクタで以下の値を受け取る
    1. String name
    2. int age
  3. その値を、コンストラクタで以下のpublicプロパティに代入する
    1. name > this.name
    2. age > this.age

穂乃果「はーい! これくらい簡単だよ!」

class Member {
	public String name;
	public int age;
	public Member(String name, int age) {
		this.name = name;
		this.age = age;
	}
}

ことり「よくできました☆」ナデナデ
穂乃果「わーい! わーい!」エヘヘヘヘ

ことり「このコードをHaskellに直していくね」
ことり「Haskellでは、代数的データ型をdataというキーワードを使って、作っていきます」

data Member = Member String Int

穂乃果「すごーい! 1行で書けちゃうんだー!」
ことり「うん、Haskellはよく、記述量が少ないって言われるんだー。 って穂乃果ちゃん、これくらいは授業でも見たはずじゃ……」
穂乃果「えへへ、実はdataがこういうのを作るものだってことも、まだわかってなくて……」

穂乃果「あれ、でもnameとか、ageっていう名前は書かないでいいの?」
ことり「うん、Haskellではプロパティ名みたいなものが必要ないことが多くって、そういう場合はつけないかなぁ」
ことり「名前をつけることもできるんだけど、今はまだ置いておいてね」
穂乃果「はい。 ことり先生!」
ことり「ことり先生なんて……エヘヘ」

ことり「これを実際に使うには……そうだ穂乃果ちゃん。 mainってもう習ったかなあ?」
穂乃果「習った! 穂乃果、mainならわかるよ!」

main :: IO ()
main = do
  print 10

穂乃果「こういうやつ!」
ことり「さすが穂乃果ちゃん♪」
穂乃果「あっでもね……:: IO ()とか、doとかもよくわかってなくって……」
ことり「大丈夫だよ、そこらへんもおいおいやっていくからね!」
穂乃果「お願いしますことり先生ー!!」ドゲザー

ことり「じゃあこれDataType.hsっていうファイル名で保存して、実行……っと」

$ stack runghc -- DataType.hs
10

穂乃果「10が表示されたね! これくらいなら穂乃果もわかるよっ!」
ことり「さすがさすが♪」

ことり「じゃあちょっと前の内容に戻って……Javaで、Memberクラスのインスタンスを生成するコードを書いてみてくれるかな」

public class Test {
	public static void main(String[] args) {
		Member kotori = new Member("南ことり", 16);
	}
}

穂乃果「こんな感じ?」
ことり「そんな感じだね、ありがとう♪ これをHaskellに直すとこうなるよ」

main :: IO ()
main = do
  let kotori = Member "南ことり" 16
  return ()

穂乃果「let? return ()?」
ことり「letは変数の定義に使うキーワードだよ! Haskellだと、変数名の前に型名を書かなくてもいいの!」
ことり「return ()は……今は単なるno operationだと思っておいて欲しいな☆」
穂乃果「no operationは、何もしない命令だったよね。 わかりましたっ!」

型クラスの自動導出

ことり「次は、Memberデータ型をmainで表示してみるよ」

ことり「Javaでは、toString()っていうメソッドをオーバーライドすることがあったよね」
穂乃果「クラスインスタンスをprintするときに、いい感じにするあれ……だよね?」

class Member {
	public String name;
	public int age;
	public Member(String name, int age) {
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString() {
		return "Member " + this.name + " " + this.age;
	}
}

ことり「そうそう! これはこう書けるよ」

data Member = Member String Int
  deriving (Show)

ことり「deriving (Show)って行を追加したよ」
穂乃果「これも1行で書けちゃうの!?」
ことり「うん、そうなんだ♪ でも、もっと表示結果をカスタマイズしたいときは、もうちょっと書く必要があるかな」
ことり「こういう単純なパターンを実装したい時には、derivingっていうのを使うよ!

main :: IO ()
main = do
  let kotori = Member "南ことり" 16
  print kotori

ことり「実行っと」

$ stack runghc -- DataType.hs
Member "南ことり" 16

穂乃果「すごーい! ちゃんと表示されたー!」
ことり「やったね!」

穂乃果「でもことりちゃん、このShowってなに?」
ことり「それはね穂乃果ちゃん、いわゆる型クラスって言って……」

…………

(次回に続く)

参考にしたページ


 疑問点があれば、Twitterでリプライくれれば(そのリプライを見逃してなければ)返すよ!
@public_ai000ya - Twitter

筆者プロフィール

my-latest-logo

aiya000(あいや)

せつラボ 〜圏論の基本〜」 「せつラボ2~雲と天使と関手圏~」 「矢澤にこ先輩といっしょに代数!」を書いています!

強い静的型付けとテストを用いて、バグを防ぐのが好き。Haskell・TypeScript。