この式は、 Factorプログラミング言語(関数の合成が物事を行う方法であり、ほとんどのコードがポイントフリーの方法で記述されている言語)で非常にエレガントに記述できます。スタックセマンティクスと行多相は、このスタイルのプログラミングを容易にします。これは、Factorで問題の解決策がどのようになるかを示しています。
# We find the longer of two lists here. The expression returns { 4 5 6 7 8 }
{ 1 2 3 } { 4 5 6 7 8 } [ [ length ] bi@ > ] 2keep ?
# We find the shroter of two lists here. The expression returns { 1 2 3 }.
{ 1 2 3 } { 4 5 6 7 8 } [ [ length ] bi@ < ] 2keep ?
ここで私たちが興味を持っているのはコンビネータ2keep
です。これは「データフローコンビネータの保持」であり、指定された機能が実行された後も入力を保持することを意味します。
このソリューション(一種)をScalaに変換してみましょう。
まず、arity-2保存コンビネータを定義します。
scala> def keep2[A, B, C](f: (A, B) => C)(a: A, b: B) = (f(a, b), a, b)
keep2: [A, B, C](f: (A, B) => C)(a: A, b: B)(C, A, B)
そしてeagerIf
コンビネータ。if
制御構造であることは、関数合成では使用できません。したがって、この構成。
scala> def eagerIf[A](cond: Boolean, x: A, y: A) = if(cond) x else y
eagerIf: [A](cond: Boolean, x: A, y: A)A
また、on
コンビネータ。Scalazの同じ名前のメソッドと衝突するため、upon
代わりに名前を付けます。
scala> class RichFunction2[A, B, C](f: (A, B) => C) {
| def upon[D](g: D => A)(implicit eq: A =:= B) = (x: D, y: D) => f(g(x), g(y))
| }
defined class RichFunction2
scala> implicit def enrichFunction2[A, B, C](f: (A, B) => C) = new RichFunction2(f)
enrichFunction2: [A, B, C](f: (A, B) => C)RichFunction2[A,B,C]
そして今、この機械を使用してください!
scala> def length: List[Int] => Int = _.length
length: List[Int] => Int
scala> def smaller: (Int, Int) => Boolean = _ < _
smaller: (Int, Int) => Boolean
scala> keep2(smaller upon length)(List(1, 2), List(3, 4, 5)) |> Function.tupled(eagerIf)
res139: List[Int] = List(1, 2)
scala> def greater: (Int, Int) => Boolean = _ > _
greater: (Int, Int) => Boolean
scala> keep2(greater upon length)(List(1, 2), List(3, 4, 5)) |> Function.tupled(eagerIf)
res140: List[Int] = List(3, 4, 5)
このアプローチはScalaでは特にエレガントに見えませんが、少なくとももう1つの方法を示しています。