Scalaを使わない1年が過ぎた。しかしFPとKotlinとSwiftを鍛えた今ならFPinScalaの資産を使い回せるはずだ。
(前にもScala→Swiftしようとしたけど不足しているものが多すぎてちからつきた。)
FPinScalaのコードは省略。Scalaの記事だけど著作権怖いから手元でみてください。
代表して10章モノイドをトライ。
ここ最近の私の周辺のScala事情
大学生です。
- コップ本の存在は(一部には)知られているらしい。生協にも置いてある。FPinScalaはわからない。
- PHPerサークルの後輩達の何人かがScalaに浮気したり異動したりしているらしい。Javaライクな書き方に留まっているのか深淵を覗く勢いなのかまでは聞いてない。
- 大学のグループ課題でわざわざScalaを選ぶ奴はいない。共通語はJava、あとは学習コストが少なくて済むRailsに飛びつく。よしみんなで1からScalaやろうぜとはならない。ダメ絶対。
すっかりFPを勉強するためだけのScalaになってしまった。Haskell書かないのにすごいHaskell読んでる感じ。
以下本題。
第10章モノイド
trait Monoid[A]
- Kotlin
-
trait
は廃止
-
- Swift
-
protocol Monoid<A>
という書き方はできない。 - なぜ
static
かは後述
-
interface Monoid<A> {
fun op(a1: A, a2: A): A
val zero: A
}
protocol Monoid {
associatedtype A
static func op(a1: A, a2: A) -> A
static var zero: A { get }
}
Monoidインスタンス
- Kotlin
- 関数を引数に使用する時は
::hoge
とすればよいが、メソッドを引数に使用することはできない(らしい)。→Kotlin: how to pass a function as parameter to another? - Stack Overflow - Scalaでいう
foldLeft
とfoldRight
はKotlinではfold
とfoldRight
。
- 関数を引数に使用する時は
- Swift
-
struct
にするのが正解なのかは謎。でも呼ぶにはそうせざるを得ない気がする。 - 相変わらず
foldLeft
をreduce
と呼ぶ謎。foldRight
は存在しないはず。
-
val stringMonoid = object: Monoid<String> {
override fun op(a1: String, a2: String): String = a1 + a2
override val zero = ""
}
class ListMonoid<A>: Monoid<List<A>> {
override fun op(a1: List<A>, a2: List<A>) = a1.plus(a2)
override val zero = listOf<A>()
}
struct StringMonoid: Monoid {
typealias A = String
static func op(a1: String, a2: String) -> String {
return a1 + a2
}
static var zero: String {
return ""
}
}
struct ArrayMonoid<T>: Monoid {
typealias A = [T]
static func op(a1: [T], a2: [T]) -> [T] {
return a1 + a2
}
static var zero: Array<T> {
return []
}
}
実際にはこんなことしないで
let s = words.fold("") { a, b -> a + b }
とか
let s = words.reduce("", +)
とか書くんだろうけど。
珍しくSwiftが1番短い。でもreduceかっこ悪い。
sealed trait WC
- Kotlin
- data classは他から継承できないので、Scala版のようにはいかない。まあ何とかなるかな?
sealed class WC {
class Stub(val chars: String): WC()
class Part(val lStub: String, val words: Int, val rStub: String): WC()
}
enum WC {
case stub(chars: String)
case part(lStub: String, words: Int, rStub: String)
}
調べてる過程でこういうの見つけた。
Scala vs Kotlin – Agilewombat
mapMergeMonoid
- Kotlin
-
class MapMergeMonoid<K, V>(val monoidV: Monoid<V>): Monoid<Map<K, V>>
などと書き出せばいけないこともないけど、結局staticメソッドを持ってこれない問題が残る。
-
- Swift
- Scala/KotlinみたいにProtocolが総称型を扱えないので
class AnyMonoid<V>: Monoid
をかませないと大変なことになりそう。
- Scala/KotlinみたいにProtocolが総称型を扱えないので
こいつはしんどい。Scalaのかち。
まとめ
最近はいろんな言語が関数型を扱えるようになって、いろいろ遊ぶのに必要な関数 ( map
とか) も増えてきた。しかし型の表現ではやはり制約がついて、Scalaみたいに直感的に書くほどには至らず、概念を各言語に落とし込むには手間がかかる。やっぱりクラスやインターフェースに落とさずに直接操作するのが無難そう。
Scala先輩はやっぱりすごい!