如有必要,尽早收集行动和分支

时间:2016-03-21 23:04:02

标签: haskell monads

我正在将一些Python代码转换为Haskell。业务逻辑相当复杂,我的Haskell代码变得丑陋。

我的Python功能:

def f(some_state):
    doAction1() # e.g. send_message("Hi there!")
    if not userIsAuthenticated:
        doAction2() # e.g. send_message("Please login")
        return
    if not userHasPermission:
        doAction3() # e.g. send_message("Please sudo")
        return
    if somePredicate3:
        doAction4()
        if somePredicate4:
            doAction5()
    return

我对Haskell版本有两个约束:

  1. 为了保持我的代码纯粹可能,我想在列表中收集我的所有动作(或者如果我感觉很好看,则收集免费Monad)然后(在函数外部)执行它。在Python中,我会在函数的开头定义tmp = [],将所有动作追加到tmp(不调用它们)并返回tmp。然后,我会遍历列表来执行所有操作(根本不是Pythonic!)。
  2. 最终会像这样被推向正确的疯狂:
  3. -

    if a
    then undefined
    else if b
         then undefined
         else if c
              then undefined
              else if d
                   then undefined
                   else undefined
    

    基本上,我想收集行动清单并在必要时尽早退出,以便我可以写下这样的内容:

    tell Action1
    when somePredicate1 $ tell doAction2
    when somePredicate2 $ tell doAction3
    ...
    

    tell不是来自编写者monad,但是它是一个函数(它不存在)聚合到目前为止“告诉”的所有内容(作者monad)并在退出时返回。 / p>

    这真的感觉像是一个广义的Either monad,除了我需要保留在第一个Left之前发生的所有动作(而不仅仅是Left值)然后在第一个Left的早期退出。我认为解决方案可能以某种方式建立在MonadPlus或Alternative上,但我无法弄清楚一些不错的东西。基本上是一种花哨的guard

    我也绝对有可能过度设计这个过程,我应该接受我的代码必须向右移动。但这不会很优雅,不是吗?

    编辑:为清楚起见,我想要一个f :: State -> [Action]类型的函数,其中data Action = Action1 | Action2 | Action3

1 个答案:

答案 0 :(得分:2)

这听起来像import org.apache.spark.ml.{Pipeline, PipelineModel} import org.apache.spark.ml.classification.LogisticRegression import org.apache.spark.ml.evaluation.BinaryClassificationEvaluator import org.apache.spark.ml.tuning.{ParamGridBuilder, CrossValidator} import org.apache.spark.mllib.linalg.Vector import java.io._ import org.apache.spark.mllib.util.MLUtils import org.apache.log4j.Logger import org.apache.log4j.Level Logger.getLogger("org").setLevel(Level.OFF) Logger.getLogger("akka").setLevel(Level.OFF) val training = sqlContext.read.format("libsvm").option("numFeatures", "2564828").load("/path/to/large/libsvm/training/data") val test = sqlContext.read.format("libsvm").option("numFeatures", "2564828").load("/path/to/large/libsvm/test/data") val lr = (new LogisticRegression()).setMaxIter(100).setElasticNetParam(1.0).setRegParam(0.1) val lrm = lr.fit(training) val output = lrm.transform(test) val evaluator = (new BinaryClassificationEvaluator()) val metric = evaluator.evaluate(output) 的理想用法,来自mtl的Control.Monad.Except,如下所示:

throwError