Magnolia Tech

いつもコードのことばかり考えている人のために。

『Scala関数型デザイン&プログラミング』の演習問題をScala3で解く その2

blog.magnolia.tech

前回のエントリの続き。

演習問題を解いていきます。

第1章はざっと読み進めて、さっさと演習問題が始まる第2章へ進みましょう(コーヒーの支払いのところとか若干???みたいな感じもあるし)。

第2章 Scala関数型プログラミングの準備

第2章も前半はScalaの言語仕様の解説なので、ざっと読み進めていけばよく、「2.6 型に従う実装」あたりから段々と本書らしい内容になっていきます。

早速実装を始めていきます。

実装の前に、必ずEXERCISEの番号をコメントで追加しておくと後から見返しやすくなります。

object PolymorphicFunctions:

  // EXERCISE 2.3
  def curry[A,B,C](f: (A, B) => C): A => (B => C) = ???

end PolymorphicFunctions

テストコードも用意します。EXERCISE 2.3のお題であるcurryは、標準ライブラリにも同様の仕様であるcurriedというメソッドが用意されているので、テストにもそちらを使ってみましょう。

package fpinscala.gettingstarted

import wvlet.airspec.*

class GettingStartedSpec extends AirSpec:

  // EXERCISE 2.3
  test("curry") {
    val f = (a: Int, b: Double) => a.toString + " & " + b.toString

    PolymorphicFunctions.curry(f)(42)(4.2) shouldBe f.curried(42)(4.2)
  }

end GettingStartedSpec

続くEXERCISE 2.4のuncurriedに該当するメソッドは用意されていませんが、curriedを適用した結果にuncurriedを適用すれば元の関数に戻るはずです。

uncurryの型シグニチャ

// EXERCISE 2.4
def uncurry[A,B,C](f: A => B => C): (A, B) => C = ???

テストコード

// EXERCISE 2.4

test("uncurry") {
  val f = (a: Int, b: Double) => a.toString + " & " + b.toString

  PolymorphicFunctions.uncurry(f.curried)(42, 4.2) shouldBe f(42, 4.2)
}

EXERCISE 2.5のcomposeは、標準ライブラリに同名のcomposeが用意されています。

composeの型シグニチャ

// EXERCISE 2.5
def compose[A,B,C](f: B => C, g: A => B): A => C = ???

テストコード

// EXERCISE 2.5
test("compose") {
  val g = (a: Int) => a.toString
  val f = (b: String) => "The answer is " + b

  PolymorphicFunctions.compose(f, g)(42) shouldBe (f compose g)(42)

なお、カリー化や、関数の合成の解説は英語版のWikipediaが充実しています(FP in ScalaWikiにもリンクが貼られています)。

Currying - Wikipedia

Function composition - Wikipedia

おわりに

次は第3章へ進みます。