如何修复此 Haskell 查找函数类型不匹配?
How to fix this Haskell lookup function type mismatch?
如果有人可以帮助修复此错误,我们将不胜感激。代码是:
type Name = String
type Coordinates = (Int, Int)
type Pop = Int
type TotalPop = [Pop]
type City = (Name, (Coordinates, TotalPop))
testData :: [City]
testData = [("New York City", ((1,1), [5, 4, 3, 2])),
("Washingotn DC", ((3,3), [3, 2, 1, 1])),
("Los Angeles", ((2,2), [7, 7, 7, 5]))]
getCityPopulation :: [City] -> Name -> Int -> Int
getCityPopulation cs nameIn yearIn = head ([ z !! (yearIn - 1) | (x,z) <- lookup nameIn cs])
预期行为:
getCityPopulation testData "New York City" 2
>>> 4
实际行为:
• Couldn't match expected type ‘[(a0, [Int])]’
with actual type ‘Maybe (Coordinates, TotalPop)’
• In the expression: lookup nameIn cs
In a stmt of a list comprehension: (x, z) <- lookup nameIn cs
In the first argument of ‘head’, namely
‘([z !! (yearIn - 1) | (x, z) <- lookup nameIn cs])’
|
55 | getCityPopulation cs nameIn yearIn = head ([ z !! (yearIn - 1) | (x,z) <- lookup nameIn cs])
| ^^^^^^^^^^^^^^^^
getCityPopulation :: [City] -> Name -> Int -> Int
getCityPopulation [] nameIn yearIn = error "Can't be empty"
getCityPopulation cs nameIn yearIn =
head ([ z !! (yearIn - 1) | (x,z) <- maybeToList $ lookup nameIn cs])
完成任务。这使用
maybeToList :: Maybe a -> [a] -- Defined in `Data.Maybe'
需要转换
的输出
lookup :: Eq a => a -> [(a, b)] -> Maybe b
当然该代码实际上应该是
head ([ z !! (yearIn - 1) | (x,z) <- maybeToList $ lookup nameIn cs])
==
case (lookup nameIn cs) of
Just (x,z) -> z !! (yearIn - 1)
Nothing -> error "couldn't find it"
这样
> getCityPopulation testData "New York City" 2
4
> getCityPopulation testData "Las Vegas" 2
*** Exception: couldn't find it
但是编写这样一个可能会失败的代码也是不对的。最好再次将结果包装在 Maybe
:
中
getCityPopulation :: [City] -> Name -> Int -> Maybe Int
getCityPopulation [] nameIn yearIn = error "Can't be empty"
getCityPopulation cs nameIn yearIn =
case (lookup nameIn cs) of
Just (x,z) -> Just $ z !! (yearIn - 1)
Nothing -> Nothing
然后我们有
> getCityPopulation testData "New York City" 2
Just 4
> getCityPopulation testData "Las Vegas" 2
Nothing
现在,更改输出类型后,我们实际上可以返回到原始代码 -- 几乎:
getCityPopulation :: [City] -> Name -> Int -> Maybe Int
getCityPopulation [] nameIn yearIn = error "Can't be empty"
getCityPopulation cs nameIn yearIn =
[ z !! (yearIn - 1) | (x,z) <- lookup nameIn cs]
你问这是什么魔法?它被称为 MonadComprehensions
。您可以在 GHCi 提示符下使用
打开它
> :set -XMonadComprehensions
或通过包含
{-# LANGUAGE MonadComprehensions #-}
pragma 在源文件的顶部。
尽管您的代码存在 no magic fix 可能存在的越界访问问题,但未检查就使用 !!
。或者有没有?
getCityPopulation :: [City] -> Name -> Int -> Maybe Int
getCityPopulation [] nameIn yearIn = error "Can't be empty"
getCityPopulation cs nameIn yearIn =
[ e | (_,z) <- lookup nameIn cs,
e <- listToMaybe $ drop (yearIn-1) z ]
lookup :: Eq a => a -> [(a, b)] -> Maybe b
return 一个 Maybe b
,而不是匹配的 b
列表。如果它在元组列表中找不到键,Nothing
是 returned,否则它是 Just somecity
.
getCityPopulation :: [City] -> Name -> Int -> Int
getCityPopulation cs nameIn yearIn = … (lookup nameIn cs)
现在我们有了 Maybe City
,我们必须决定在 Nothing
的情况下要做什么,例如 return -1
在这种情况下.为此,我们可以使用 Maybe
类型的 catamorphism:maybe :: b -> (a -> b) -> b
,因此我们可以指定在 Nothing
的情况下要做什么,然后我们传递一个函数,在 Just x
和 x
:
的情况下该怎么做
import Data.Maybe(maybe)
getCityPopulation :: [City] -> Name -> Int -> Int
getCityPopulation cs nameIn yearIn = <b>maybe (-1)</b> (…) (lookup nameIn cs)
现在…
是一个City
,我们需要检索年份,我们可以使用snd :: (a, b) -> b
获取人口列表,然后查找相关人口, 所以:
import Data.Maybe(maybe)
getCityPopulation :: [City] -> Name -> Int -> Int
getCityPopulation cs nameIn yearIn = maybe (-1) (<b>(!! yearIn) . snd</b>) (lookup nameIn cs)
然而,返回一个简单的 Int
对于可能会失败的计算来说并不是很“Haskellish”,通常在这种情况下 return 类型是Maybe Int
如果结果应该是 Int
但可能会失败。我们可以使用 fmap :: Functor f => (a -> b) -> f a -> f b
映射包装在 Just
数据构造函数中的值,或者如果我们映射 Nothing
,则使用 Nothing
,那么函数看起来像:
getCityPopulation :: [City] -> Name -> Int -> <b>Maybe Int</b>
getCityPopulation cs nameIn yearIn = <b>fmap</b> ((!! yearIn) . snd) (lookup nameIn cs)
然后我们得到例如:
Prelude> getCityPopulation testData "New York" 2
Nothing
Prelude> getCityPopulation testData "New York City" 2
Just 3
(!!)
函数也不是很安全,因为 yearIn
的值可能小于 0
或大于或等于人口名单。我把它留作练习,以实现更安全的 varint。
如果有人可以帮助修复此错误,我们将不胜感激。代码是:
type Name = String
type Coordinates = (Int, Int)
type Pop = Int
type TotalPop = [Pop]
type City = (Name, (Coordinates, TotalPop))
testData :: [City]
testData = [("New York City", ((1,1), [5, 4, 3, 2])),
("Washingotn DC", ((3,3), [3, 2, 1, 1])),
("Los Angeles", ((2,2), [7, 7, 7, 5]))]
getCityPopulation :: [City] -> Name -> Int -> Int
getCityPopulation cs nameIn yearIn = head ([ z !! (yearIn - 1) | (x,z) <- lookup nameIn cs])
预期行为:
getCityPopulation testData "New York City" 2
>>> 4
实际行为:
• Couldn't match expected type ‘[(a0, [Int])]’
with actual type ‘Maybe (Coordinates, TotalPop)’
• In the expression: lookup nameIn cs
In a stmt of a list comprehension: (x, z) <- lookup nameIn cs
In the first argument of ‘head’, namely
‘([z !! (yearIn - 1) | (x, z) <- lookup nameIn cs])’
|
55 | getCityPopulation cs nameIn yearIn = head ([ z !! (yearIn - 1) | (x,z) <- lookup nameIn cs])
| ^^^^^^^^^^^^^^^^
getCityPopulation :: [City] -> Name -> Int -> Int
getCityPopulation [] nameIn yearIn = error "Can't be empty"
getCityPopulation cs nameIn yearIn =
head ([ z !! (yearIn - 1) | (x,z) <- maybeToList $ lookup nameIn cs])
完成任务。这使用
maybeToList :: Maybe a -> [a] -- Defined in `Data.Maybe'
需要转换
的输出lookup :: Eq a => a -> [(a, b)] -> Maybe b
当然该代码实际上应该是
head ([ z !! (yearIn - 1) | (x,z) <- maybeToList $ lookup nameIn cs])
==
case (lookup nameIn cs) of
Just (x,z) -> z !! (yearIn - 1)
Nothing -> error "couldn't find it"
这样
> getCityPopulation testData "New York City" 2
4
> getCityPopulation testData "Las Vegas" 2
*** Exception: couldn't find it
但是编写这样一个可能会失败的代码也是不对的。最好再次将结果包装在 Maybe
:
getCityPopulation :: [City] -> Name -> Int -> Maybe Int
getCityPopulation [] nameIn yearIn = error "Can't be empty"
getCityPopulation cs nameIn yearIn =
case (lookup nameIn cs) of
Just (x,z) -> Just $ z !! (yearIn - 1)
Nothing -> Nothing
然后我们有
> getCityPopulation testData "New York City" 2
Just 4
> getCityPopulation testData "Las Vegas" 2
Nothing
现在,更改输出类型后,我们实际上可以返回到原始代码 -- 几乎:
getCityPopulation :: [City] -> Name -> Int -> Maybe Int
getCityPopulation [] nameIn yearIn = error "Can't be empty"
getCityPopulation cs nameIn yearIn =
[ z !! (yearIn - 1) | (x,z) <- lookup nameIn cs]
你问这是什么魔法?它被称为 MonadComprehensions
。您可以在 GHCi 提示符下使用
> :set -XMonadComprehensions
或通过包含
{-# LANGUAGE MonadComprehensions #-}
pragma 在源文件的顶部。
尽管您的代码存在 no magic fix 可能存在的越界访问问题,但未检查就使用 !!
。或者有没有?
getCityPopulation :: [City] -> Name -> Int -> Maybe Int
getCityPopulation [] nameIn yearIn = error "Can't be empty"
getCityPopulation cs nameIn yearIn =
[ e | (_,z) <- lookup nameIn cs,
e <- listToMaybe $ drop (yearIn-1) z ]
lookup :: Eq a => a -> [(a, b)] -> Maybe b
return 一个 Maybe b
,而不是匹配的 b
列表。如果它在元组列表中找不到键,Nothing
是 returned,否则它是 Just somecity
.
getCityPopulation :: [City] -> Name -> Int -> Int
getCityPopulation cs nameIn yearIn = … (lookup nameIn cs)
现在我们有了 Maybe City
,我们必须决定在 Nothing
的情况下要做什么,例如 return -1
在这种情况下.为此,我们可以使用 Maybe
类型的 catamorphism:maybe :: b -> (a -> b) -> b
,因此我们可以指定在 Nothing
的情况下要做什么,然后我们传递一个函数,在 Just x
和 x
:
import Data.Maybe(maybe)
getCityPopulation :: [City] -> Name -> Int -> Int
getCityPopulation cs nameIn yearIn = <b>maybe (-1)</b> (…) (lookup nameIn cs)
现在…
是一个City
,我们需要检索年份,我们可以使用snd :: (a, b) -> b
获取人口列表,然后查找相关人口, 所以:
import Data.Maybe(maybe)
getCityPopulation :: [City] -> Name -> Int -> Int
getCityPopulation cs nameIn yearIn = maybe (-1) (<b>(!! yearIn) . snd</b>) (lookup nameIn cs)
然而,返回一个简单的 Int
对于可能会失败的计算来说并不是很“Haskellish”,通常在这种情况下 return 类型是Maybe Int
如果结果应该是 Int
但可能会失败。我们可以使用 fmap :: Functor f => (a -> b) -> f a -> f b
映射包装在 Just
数据构造函数中的值,或者如果我们映射 Nothing
,则使用 Nothing
,那么函数看起来像:
getCityPopulation :: [City] -> Name -> Int -> <b>Maybe Int</b>
getCityPopulation cs nameIn yearIn = <b>fmap</b> ((!! yearIn) . snd) (lookup nameIn cs)
然后我们得到例如:
Prelude> getCityPopulation testData "New York" 2
Nothing
Prelude> getCityPopulation testData "New York City" 2
Just 3
(!!)
函数也不是很安全,因为 yearIn
的值可能小于 0
或大于或等于人口名单。我把它留作练习,以实现更安全的 varint。