我想知道如何返回一个非常简单的字符串异常.我写了一个函数"powered",取一个整数n,并返回2 ^(n).这是代码:
powered::Int->Int
powered n
| n==1 =2
| otherwise =iter n double 1
Run Code Online (Sandbox Code Playgroud)
iter:
iter::Int->(Int->Int)->Int->Int
iter n f x
| n==1 =f x
| n>1 =iter (n-1) f (f x)
| otherwise =x
Run Code Online (Sandbox Code Playgroud)
和双:
double::Int->Int
double n = n*2
Run Code Online (Sandbox Code Playgroud)
此代码适用于所有自然数字.但是,我想说,如果我向它传递一个负整数,它会返回一个字符串异常,说:"输入不正确".我怎样才能做到这一点.这是我想要完成的伪代码:
powered::Int->Int
powered n
| n==0 =1
| n==1 =2
| n>1 =iter n double 1
| otherwise ="Incorrect input"
main = do
print(powered (-1)) ~> "Incorrect input"
Run Code Online (Sandbox Code Playgroud)
Ben*_*son 10
Haskell的异常系统故意不足.您无法在纯代码中捕获异常,因此异常处理只能在IOmonad 中的非常粗粒度级别进行.很难 - 尽管可能 - 阻止异常完全崩溃您的程序.(想象一下,如果你只能写一个命令式程序catch的main方法!)我们因此避免在可能的情况下抛出异常; 有一个更好的选择.
在Haskell中进行异常样式编程的"正确方法"是利用类型系统.在这里,我Either用来表示计算失败的可能性.
powered :: Int -> Either String Int
powered n
| n <= 0 = Left "Incorrect input"
| n==1 = Right 2 -- Right means "the right answer"
| otherwise = Right $ iter n double 1
Run Code Online (Sandbox Code Playgroud)
如果我们无法计算答案,则返回包含错误消息的Leftvalue(Left :: a -> Either a b)String.否则我们返回一个包含答案的Right(Right :: b -> Either a b).
编译器强制调用者powered检查返回值以确定计算是否失败.如果不处理或传播可能的错误,您根本无法获得计算结果.
我们可以更进一步.我们可以编码一个事实,即powered期望一个正整数进入类型签名本身.如果我们正确构造代码,编译器将确保没有人尝试使用负整数调用它.
-- file Natural.hs
-- don't export the 'Natural' value constructor: 'mkNatural' acts as our "gatekeeper"
module Data.Natural (Natural, toInt, mkNatural) where
newtype Natural = Natural {toInt :: Int} deriving (Eq, Show)
mkNatural :: Int -> Either String Natural
mkNatural x
| x <= 0 = Left "Must be greater than 0"
| otherwise = Right $ Natural x
Run Code Online (Sandbox Code Playgroud)
Natural是一种包装的类型Int.作为Data.Natural模块的客户端,只有一种方法可以Natural:通过调用mkNatural"智能构造函数",mkNatural当它的参数不是自然数时,你会看到失败.所以Natural没有正整数就不可能.我们还提供了相反的方法,toInt :: Natural -> Int以提取底层Int从Natural.
现在我们可以编写以下类型签名powered,这使得无法使用无效输入调用该函数:
powered :: Natural -> Natural
Run Code Online (Sandbox Code Playgroud)
这是更具表现力的方式:类型签名清楚地表明这powered是对返回新自然数的自然数的操作.(我将把它作为练习让你powered用这种类型实现.)通过将输入验证的关注点分成新类型,我们最终得到了更清晰的代码.