Scala functional programming gymnastics

后端 未结 13 690
悲&欢浪女
悲&欢浪女 2021-02-01 09:36

I am trying to do the following in as little code as possible and as functionally as possible:

def restrict(floor : Option[Double], cap : Option[Double], amt : D         


        
13条回答
  •  梦毁少年i
    2021-02-01 10:32

    Edit 2:

    While thinking about the cataX method, I figured out that cataX is nothing else than a plain and simple fold. Using that, we can get a pure scala solution without any additional libraries.

    So, here it is:

    ( (amt /: floor)(_ max _) /: cap)(_ min _)
    

    which is the same as

    cap.foldLeft( floor.foldLeft(amt)(_ max _) )(_ min _)
    

    (not that this is necessarily easier to understand).

    I think you can’t have it any shorter than that.


    For better or worse, we can also solve it using scalaz:

    floor.map(amt max).getOrElse(amt) |> (m => cap.map(m min).getOrElse(m))
    

    or even:

    floor.cata(amt max, amt) |> (m => cap.cata(m min, m))
    

    As a ‘normal’ Scala programmer, one might not know about the special Scalaz operators and methods used (|> and Option.cata). They work as follows:

    value |> function translates to function(value) and thus amt |> (m => v fun m) is equal to v fun amt.

    opt.cata(fun, v) translates to

    opt match {
      case Some(value) => fun(value) 
      case None => v
    }
    

    or opt.map(fun).getOrElse(v).

    See the Scalaz definitions for cata and |>.

    A more symmetric solution would be:

    amt |> (m => floor.cata(m max, m)) |> (m => cap.cata(m min, m))
    

    Edit: Sorry, it’s getting weird now, but I wanted to have a point-free version as well. The new cataX is curried. The first parameter takes a binary function; the second is a value.

    class CataOption[T](o: Option[T]) {
      def cataX(fun: ((T, T) => T))(v: T) = o.cata(m => fun(m, v), v)
    }
    implicit def option2CataOption[T](o: Option[T]) = new CataOption[T](o)
    

    If o matches Some we return the function with the value of o and the second parameter applied, if o matches None we only return the second parameter.

    And here we go:

    amt |> floor.cataX(_ max _) |> cap.cataX(_ min _)
    

    Maybe they already have this in Scalaz…?

提交回复
热议问题