Vic*_*cky 8 java haskell design-patterns functional-programming clojure
让我们说,我有以下代码.
public int divide(int dividend, int divisor) {
if( divisor == 0 || (dividend == Integer.MIN_VALUE && divisor == -1))
throw new DivisionException();
return dividend/divisor;
}
Run Code Online (Sandbox Code Playgroud)
如何在函数式编程中编写?
我有一个类似于上面用Java编写的逻辑,并希望将其迁移到Haskell/Clojure中的功能代码.如何在呼叫者中处理此问题divide
?
我知道上面的代码是完全必要的.它不是在未来将其迁移到FP的预先编写的.
请在Haskell或Clojure中使用示例代码告诉我.
Rom*_*man 10
以下显示了如何在Haskell中完成它.
根据类型siginure,divide :: Int -> Int -> Either [Char] Int
您可以看到该函数divide
将返回a Left string
或a Right Int
.
Either
是一个代数数据结构,还有更多,你可以自己编写.
divide :: Int -> Int -> Either [Char] Int
divide dividend divisor
| (divisor == 0) = Left "Sorry, 0 is not allowed :o"
| (dividend == (minBound :: Int)) && (divisor == -1) = Left "somethig went wrong"
| otherwise = Right (dividend `div` divisor)
main = do
print (divide 4 2) -- Right 2
print (divide 4 0) -- Left "Sorry, 0 is not allowed :o"
print (divide (minBound :: Int) (-1)) -- Left "somethig went wrong"
Run Code Online (Sandbox Code Playgroud)
你可以在repl.it上玩它
在Haskell中你可以抛出错误,error "and your error message"
但这会让你崩溃..这不是我们想要的.
该divide
函数不是全部:其输入域中的某些值没有图像。
更改输出域,使其可以返回错误或数字。调用者负责检查该值是否真的是一个数字,还是一个错误。
在像 Clojure 这样的动态类型语言中,您可以 return nil
,但任何其他值也可以工作,只要您能将它与数字区分开来。在像 Haskell 这样的静态类型语言中,Data.Either
如果需要,请使用或您自己的数据类型。
该检查在 Haskell 中以一致且静态的方式完成。您必须每次都进行检查,即使您确定除数不能为空。但是,您也可以拥有一个包装函数 ,must-divide
然后它会在出现错误时引发异常。
在 Clojure 中,您可能会忘记检查nil
,可能是因为错误,或者是因为您比编译器拥有更多关于除数的信息。但是,您可以通过导出divide
需要您考虑错误路径的宏来强制进行一致检查:
(divide x y :on-error (throw ...))
(divide x y :on-error default-value)
Run Code Online (Sandbox Code Playgroud)
...可以分别扩展为:
(or (maybe-divide x y) (throw ...))
(or (maybe-divide x y) default-value)
Run Code Online (Sandbox Code Playgroud)
... 和
(defn maybe-divide [dividend divisor]
(and (not (zero? divisor))
(or (not= Integer/MIN_VALUE dividend)
(not= -1 divisor))
(/ dividend divisor)))
Run Code Online (Sandbox Code Playgroud)数学运算被组合成更大的表达式:在其中添加显式错误处理路径可能很快变得不可读。此外,您可能希望您的大部分操作都divide
使用有效输入进行调用,并且不想在每次调用时检查结果是否有效(例如,某些数学方程带有证明除数永远不可能是空值)。在这种情况下,Clojure 和 Haskell 支持异常。这允许您在有错误的情况下在调用堆栈中捕获更高的错误。
在 Clojure 中,这与 Java 没有什么不同:
(defn divide
[dividend divisor]
(if (or (zero? divisor)
(and (= Integer/MIN_VALUE
dividend)
(= -1 divisor)))
(throw (DivisionException.))
(/ dividend divisor)))
Run Code Online (Sandbox Code Playgroud)
您的代码不会改变任何变量,因此已经非常实用。异常也是 Clojure 的一部分,因为它采用了 JVM 的执行模型。