为什么我的(替代!!)函数有这种类型
why does my (alternative to !!) function have this type
对某些前奏函数(如 !!)给出的错误消息感到有点沮丧,我尝试编写一个不同的版本。
--(!!!) :: (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]
我不明白为什么这里的第一个参数被推断为一个字符串列表,而不是一个 show 实例列表。有人能解释一下吗?
你需要在最后一行加上括号(或 $
):
error ("!!!: list "++(show as)++" has less than "++show y++" elements")
现在它被解析为
(error "!!!: list ") ++ (show as) ++ " has less than " ++ show y ++" elements"
这使得 Haskell 认为 (!!!)
正在返回一个字符串,这意味着它的输入必须是一个字符串列表。
这是因为您使用了error
。 error
的类型是 String -> a
,而你键入它的方式编译器将其视为
f [] _ = (error "!!!: list ") ++ (show as) ++ " has less than " ++ (show y) ++ " elements"
由于您有一个 a
类型的值与 String
连接(即 error "!!!: list " ++ show as
),那么 a
必须是 String
,因此f
的 return 类型必须是 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
对某些前奏函数(如 !!)给出的错误消息感到有点沮丧,我尝试编写一个不同的版本。
--(!!!) :: (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]
我不明白为什么这里的第一个参数被推断为一个字符串列表,而不是一个 show 实例列表。有人能解释一下吗?
你需要在最后一行加上括号(或 $
):
error ("!!!: list "++(show as)++" has less than "++show y++" elements")
现在它被解析为
(error "!!!: list ") ++ (show as) ++ " has less than " ++ show y ++" elements"
这使得 Haskell 认为 (!!!)
正在返回一个字符串,这意味着它的输入必须是一个字符串列表。
这是因为您使用了error
。 error
的类型是 String -> a
,而你键入它的方式编译器将其视为
f [] _ = (error "!!!: list ") ++ (show as) ++ " has less than " ++ (show y) ++ " elements"
由于您有一个 a
类型的值与 String
连接(即 error "!!!: list " ++ show as
),那么 a
必须是 String
,因此f
的 return 类型必须是 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