对于错误消息有点沮丧,有些前奏函数(比如!!)给出了,我试着写一个不同的版本。
--(!!!) :: (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"
但是函数类型是
*Handydandy> :type (!!!)
(!!!) :: (Show a, Num a, Eq a) => [[Char]] -> a -> [Char]
我不明白为什么第一个参数被推断为Strings列表而不仅仅是show实例列表。有人可以解释一下吗?
答案 0 :(得分:8)
在最后一行中需要一些括号(或$
):
error ("!!!: list "++(show as)++" has less than "++show y++" elements")
现在将其解析为
(error "!!!: list ") ++ (show as) ++ " has less than " ++ show y ++" elements"
这使得Haskell认为(!!!)
返回一个字符串,这意味着它的输入必须是一个字符串列表。
答案 1 :(得分:6)
这是因为您使用error
。 error
的类型为String -> a
,并且您键入的方式为编译器将其视为
f [] _ = (error "!!!: list ") ++ (show as) ++ " has less than " ++ (show y) ++ " elements"
由于您的a
类型的值与String
(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"
现在这个函数的类型是(!!!) :: (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
然后你可以
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