我使用标准的IO monad.
在某些时候,我需要短路.在给定条件下,我不想运行以下ios.
这是我的解决方案,但我发现它太冗长而且不优雅:
def shortCircuit[A](io: IO[A], continue: Boolean) =
io.map(a => if (continue) Some(a) else None)
for {
a <- io
b <- shortCircuit(io, a == 1)
c <- shortCircuit(io, b.map(_ == 1).getOrElse(false))
d <- shortCircuit(io, b.map(_ == 1).getOrElse(false))
e <- shortCircuit(io, b.map(_ == 1).getOrElse(false))
} yield …
Run Code Online (Sandbox Code Playgroud)
例如,对于第3行,第4行和第5行,我需要重复相同的条件.
有没有更好的办法 ?
你实际上并没有在那里短路任何东西。您仍在运行 IO;你只是没有捕捉到价值观。
\n\n另外,标准 IO monad 没有定义filter
(或withFilter
),因此您不能在 for 理解中使用防护。
现在,如果您想要的只是您所说的(相同的逻辑,只是更干燥),您可以随时在 for 理解中分配一个临时变量:
\n\nfor {\n a <- io\n b <- shortCircuit(io, a == 1)\n continue = b.map(_ == 1).getOrElse(false)\n c <- shortCircuit(io, continue)\n d <- shortCircuit(io, continue)\n e <- shortCircuit(io, continue)\n} yield \xe2\x80\xa6\n
Run Code Online (Sandbox Code Playgroud)\n\n但如果你真的想短路,你就必须以某种方式拆开外壳。这是一种可能性,假设您只想将所有内容打包到一个数组中,以便返回类型很简单,并且您的IO
伴生对象有一个 apply 方法,您可以使用该方法创建只返回值的对象:
io.flatMap(a =>\n if (a == 1) IO(() => Array(a))\n else io.flatMap(b =>\n if (b == 1) IO(() => Array(a,b))\n else for {\n c <- io\n d <- io\n e <- io\n } yield Array(a,b,c,d,e)\n )\n)\n
Run Code Online (Sandbox Code Playgroud)\n\n如果您的返回类型更复杂,您可能需要更加努力地指定类型。
\n\nFWIW,值得注意的是你为将东西包裹在 monad 中而付出的惩罚;如果没有,相同的逻辑将是(例如):
\n\nio() match {\n case 1 => Array(1)\n case a => io() match {\n case 1 => Array(a, 1)\n case b => Array(a, b, io(), io(), io())\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n如果您允许退货,您将得到:
\n\nval a = io()\nif (a == 1) return Array(a)\nval b = io()\nif (b == 1) return Array(a, b)\nArray(a, b, io(), io(), io())\n
Run Code Online (Sandbox Code Playgroud)\n\n原则上也可以用额外的方法来装饰 IO monad,这些方法会有所帮助,但标准withFilter
不起作用,因此您将无法使用 for-communion 语法糖。
归档时间: |
|
查看次数: |
442 次 |
最近记录: |