我正在将一些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版本有两个约束:
tmp = []
,将所有动作追加到tmp
(不调用它们)并返回tmp
。然后,我会遍历列表来执行所有操作(根本不是Pythonic!)。-
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
。
答案 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