对错误消息有点沮丧一些前奏函数(如!!)给出,我试着写一个不同的版本.
--(!!!) :: (Show a,Integral b)=> [a]->b->a
as !!! y=f as y
where f (x:xs) b= if b==0
then x
else f xs (b-1)
f [] _= error "!!!: list "++(show as)++" has less than "++show y++" elements"
Run Code Online (Sandbox Code Playgroud)
但是函数类型是
*Handydandy> :type (!!!)
(!!!) :: (Show a, Num a, Eq a) => [[Char]] -> a -> [Char]
Run Code Online (Sandbox Code Playgroud)
我不明白为什么第一个参数被推断为字符串列表而不仅仅是一个show实例列表.有人可以解释一下吗?
$在最后一行中需要一些括号(或a ):
error ("!!!: list "++(show as)++" has less than "++show y++" elements")
Run Code Online (Sandbox Code Playgroud)
现在它被解析为
(error "!!!: list ") ++ (show as) ++ " has less than " ++ show y ++" elements"
Run Code Online (Sandbox Code Playgroud)
这使得Haskell认为(!!!)返回一个字符串,这意味着它的输入必须是一个字符串列表.
这是因为你的使用error.erroris 的类型String -> a,以及你输入它的方式,编译器将其视为
f [] _ = (error "!!!: list ") ++ (show as) ++ " has less than " ++ (show y) ++ " elements"
Run Code Online (Sandbox Code Playgroud)
由于你有一个a与a String(ie error "!!!: list " ++ show as)连接的类型的值,所以a必须是String,所以返回类型f必须是String.你有f (x:xs) 0 = x,所以x必须有类型String,因此xs :: [String].
你可以解决这个问题$:
f [] _ = error $ "!!!: list " ++ show as ++ " has less than " ++ show y ++ " elements"
Run Code Online (Sandbox Code Playgroud)
现在这个功能的类型(!!!) :: (Show t, Show a, Num a, Eq a) => [t] -> a -> t更像是你想要的.
但是,如果您想要一种更好的方法来处理代码,而不仅仅是在运行时错误消息中,您可以使用Maybe数据类型,Either如果您想了解更多信息,甚至可以使用类型:
(!!?) :: [a] -> Int -> Maybe a
[] !!? _ = Nothing
(x:_) !!? 0 = Just x
(_:xs) !!? n = xs !!? (n - 1)
(!!^?) :: [a] -> Int -> Either ([a], Int) a
ys !!^? m = go ys m
where
go [] _ = Left (ys, m)
go (x:_) 0 = Right x
go (_:xs) n = go xs $ n - 1
Run Code Online (Sandbox Code Playgroud)
那你就可以了
showIndexError :: Show a => Either ([a], Int) a -> String
showIndexError (Left (xs, n)) = "!!^?: list " ++ show xs ++ " has less than " ++ show y ++ " elements"
showIndexError (Right x) = show x
Run Code Online (Sandbox Code Playgroud)