2017-07-03 42 views
3

我有一個函數,如下所示:應用所有過濾器的功能爲一個值

def createBuilder(builder: InitialBuilder, name: Option[String], useCache: Boolean, timeout: Option[Long]): Builder = { 
    val filters: List[Builder => Option[Builder]] = List(
     b => name.map(b.withName), 
     b => if (useCache) Some(b.withCache) else None, 
     b => timeout.map(b.withTimeout)) 

    filters.foldLeft(builder)((b,filter) => filter(b).getOrElse(b)) 
} 

Builder => Option[Builder]它定義3個濾波器函數(從可選參數轉換)。我想將它們應用於現有的builder值,因此在None的情況下,我可以自行返回,保持不變。

上面的代碼是我能想到的最好的代碼,但它覺得我應該以某種方式能夠用Monoid做到這一點 - 如果是None,返回identity

不幸的是,我無法弄清楚如何定義一個有意義。或者,如果有更好的/不同的方式來做到這一點?

我使用的貓,如果該事項。有任何想法嗎?

+0

*在沒有的情況下返回身份*返回身份(。零)的幺半羣?意思是如果你有一個'Monoid [String] .zero'你會返回一個空字符串,那好嗎? –

+0

@YuvalItzchakov嗯,我敢肯定,我的意思是應用'identity'函數返回初始'builder' ... –

+0

啊,所以你在談論一個'含半幺羣[生成器]'? –

回答

1

我覺得你的情況A => M[A]結構是有點畫蛇添足。您在示例中使用的過濾器功能實際上等同於Option[Builder => Builder]。這是因爲您不使用他們的參數來決定結果應該是Some還是None。您可以使用.getOrElse(identity)將功能進一步簡化爲Builder => Builder

這裏有2個實現使用了這個想法。他們甚至不依賴貓。

def createBuilder(
    builder: InitialBuilder, name: Option[String], useCache: Boolean, timeout: Option[Long] 
): Builder = { 
    def builderStage[T](param: Option[T])(modify: T => Builder => Builder): Builder => Builder = 
    param.fold(identity[Builder](_))(modify) 

    val stages: List[Builder => Builder] = List(
    builderStage(name)(n => _ withName n), 
    // `Boolean` is equivalent to `Option[Unit]`, and we convert it to that representation 
    // Haskell has a special function to do such a conversion `guard`. 
    // In Scalaz you can use an extension method `useCache.option(())`. 
    // In cats a similar `option` is provided in Mouse library. 
    // But you can just write this manually or define your own extension 
    builderStage(if (useCache)().some else none)(_ => _.withCache), 
    builderStage(timeout)(t => _ withTimeout t) 
) 

    // It should be possible to use `foldK` method in cats, to do a similar thing. 
    // The problems are that it may be more esoteric and harder to understand, 
    // it seems you have to provide type arguments even with -Ypartial-unification, 
    // it folds starting from the last function, because it's based on `compose`. 
    // Anyway, `reduceLeft(_ andThen _)` works fine for a list of plain functions. 
    stages.reduceLeft(_ andThen _)(builder) 
} 

另一種可能性是flattenOptionList的s,這隻會刪除None•不用他們強迫到identity

def createBuilder2(
    builder: InitialBuilder, name: Option[String], useCache: Boolean, timeout: Option[Long] 
): Builder = { 
    val stages: List[Option[Builder => Builder]] = List(
    name.map(n => _ withName n), 
    if (useCache) Some(_.withCache) else None, 
    timeout.map(t => _ withTimeout t) 
) 

    stages.flatten.reduceLeft(_ andThen _)(builder) 
} 
+0

令人驚歎!非常感謝,這裏值得探索的偉大創意! –