Home About Contact
Haskell , Kotlin

Haskell / コンピュータリストを操作する Haskell と Kotlin 比較

Haskell に慣れるため、Koltin と比較しながら、身近な題材を使ってあれこれやってみます。

Spread Sheet Computer List

名前+OS+価格の一覧であるコンピュータリストがあったとして、これを操作してみます。

Step1 Haskell で実装

computer.hs:

type Name = String
type Price = Int

data OS = MacOS | IOS | ChromeOS | Windows deriving (Show, Eq)
data Computer = Computer { name :: Name
                     , os :: OS
                     , price :: Price } deriving Show

computerList :: [Computer]
computerList = [ Computer "macbook air" MacOS 98000
               , Computer "macbook pro" MacOS 248000
               , Computer "iPad pro" IOS 128000
               , Computer "iPad air" IOS 68000
               , Computer "pixelbook" ChromeOS 158000
               , Computer "pixelbook Go" ChromeOS 78000
               , Computer "surface laptop" Windows 168000
               , Computer "surface laptop Go" Windows 68000
               , Computer "surface pro" Windows 198000
               , Computer "surface Go" Windows 48000
               , Computer "thinkpad x1" Windows 178000
               ]

GHCi を起動して コンピュータリストを表示し、take, drop, reverse, filter してみます。

$ ghci
> :load computer.hs
> computerList
[Computer {name = "macbook air", os = MacOS, price = 98000},Computer {name = "macbook pro", os = MacOS, price = 248000},Computer {name = "iPad pro", os = IOS, price = 128000},Computer {name = "iPad air", os = IOS, price = 68000},Computer {name = "pixelbook", os = Windows, price = 158000},Computer {name = "pixelbook Go", os = Windows, price = 78000},Computer {name = "surface laptop", os = Windows, price = 168000},Computer {name = "surface laptop Go", os = Windows, price = 68000},Computer {name = "surface pro", os = Windows, price = 198000},Computer {name = "surface Go", os = Windows, price = 48000},Computer {name = "thinkpad x1", os = Windows, price = 178000}]

先頭の2件だけ take します:

> take 2 computerList 
[Computer {name = "macbook air", os = MacOS, price = 98000},Computer {name = "macbook pro", os = MacOS, price = 248000}]

末尾の2件だけ取得します。 そのためには computerList の件数を数えて、-2 した値を使って drop:

> length computerList
> drop (11-2) computerList
[Computer {name = "surface Go", os = Windows, price = 48000},Computer {name = "thinkpad x1", os = Windows, price = 178000}]

または、リストをリバースしてから take 2 してもよい:

> take 2 $ reverse computerList
[Computer {name = "thinkpad x1", os = Windows, price = 178000},Computer {name = "surface Go", os = Windows, price = 48000}]

次に 先頭のコンピュータを取り出しOSを確認:

> head computerList
Computer {name = "macbook air", os = MacOS, price = 98000}
> os $ head computerList
MacOS

OS が iOS のコンピュータだけを取り出す:

> filter (\c -> (os c) == IOS) computerList
[Computer {name = "iPad pro", os = IOS, price = 128000},Computer {name = "iPad air", os = IOS, price = 68000}]

うまく、iOS のコンピュータだけ抽出できています。

Step2 Kotlin にしてみる

この内容を Kotlin スクリプトに置きかえて確認してみます。

computer.main.kts:

enum class OS {
    MacOS, IOS, ChromeOS, Windows
}

class Computer(val name: String, val os: OS, val price: Int){
    override fun toString(): String {
        return "<$name $os $price>"
    }
}

val computerList = listOf(
    Computer("macbook air", OS.MacOS, 98000), 
    Computer("macbook pro", OS.MacOS, 248000), 
    Computer("iPad pro", OS.IOS, 128000),
    Computer("iPad air", OS.IOS, 68000),
    Computer("pixelbook", OS.ChromeOS, 158000),
    Computer("pixelbook Go", OS.ChromeOS, 78000),
    Computer("surface laptop", OS.Windows, 168000),
    Computer("surface laptop Go", OS.Windows, 68000),
    Computer("surface pro", OS.Windows, 198000),
    Computer("surface Go", OS.Windows, 48000),
    Computer("thinkpad x1", OS.Windows, 178000) )

println( computerList )

kotlin コマンドで実行します:

$ kotlin computer.main.kts
[<macbook air MacOS 98000>, <macbook pro MacOS 248000>, <iPad pro IOS 128000>, <iPad air IOS 68000>, <pixelbook ChromeOS 158000>, <pixelbook Go ChromeOS 78000>, <surface laptop Windows 168000>, <surface laptop Go Windows 68000>, <surface pro Windows 198000>, <surface Go Windows 48000>, <thinkpad x1 Windows 178000>]

kotlin コマンドのインストール方法はこちら

うまくいきました。

それでは続いて、take, drop, reverse, filter するコードを computer.main.kts に追加。

println( "take 2 computerList" )
println( computerList.take(2) )

println( "drop (11-2) computerList" )
println( computerList.drop( computerList.size -2 ) )

println( "take 2 $ reverse computerList")
println( computerList.asReversed().take(2) )

println( "filter (\\c -> (os c) == IOS) computerList" )
println( computerList.filter( {c -> c.os == OS.IOS} ) )

Kotlin ではリストの内容を反転させるときに reverse() ではなく、asReverse() を使うことで意図通りの処理ができました。

実行してみます。

$ kotlin computer.main.kts
take 2 computerList
[<macbook air MacOS 98000>, <macbook pro MacOS 248000>]
drop (11-2) computerList
[<surface Go Windows 48000>, <thinkpad x1 Windows 178000>]
take 2 $ reverse computerList
[<thinkpad x1 Windows 178000>, <surface Go Windows 48000>]
filter (\c -> (os c) == IOS) computerList
[<iPad pro IOS 128000>, <iPad air IOS 68000>]

うまくいきました。

ほとんど Haskell と同じ感覚で Kotlin に翻訳できました。