我正在映射元组并设法使其适用于单个元组(a,a)。但是当我将元组更改为[[(a, a)]]
时,它表示"无法与预期的[(a, a)]
类型匹配(a, a)
。
mapTuple :: (a -> b) -> [[(a, a)]] -> [(b, b)]
mapTuple f [] = []
mapTuple f ((a1, a2) : xs) = (f a1, f a2) : mapTuple f xs
myfunc :: Int -> Int
myfunc xk = xk + 1
myTup = [[(1,2),(5,6),(9,10)]] :: [[(Int, Int)]]
test = mapTuple myfunc myTup
还没有打破错误。我在这里遗漏了一些东西。在此先感谢您的帮助。
答案 0 :(得分:2)
当您将类型更改为[[(a,a)]]
时,您的mapTuple无法正常工作,因为((a1, a2) : xs)
仍然具有[(a,a)]
类型。
如果您想将mapTuple应用于元组列表而不是元组列表,那么您根本不需要更改mapTuple。
让我们看一下第二种类型:
mapTuple(在更改之前)具有类型(a -> b) -> [(a,a)] -> [(b,b)]
将mapTuple部分应用于myfunc,我们得到[(a,a)] -> [(b,b)]
从评论中您需要一个需要[[(1,1),(2,2)],[(3,3)]] :: [[(a,a)]]
并返回[[(2,2),(3,3)],[(4,4)]] :: [[(b,b)]]
因此,我们希望将此部分功能应用于[(a,a)]
中的每个[[(a,a)]]
以获取[[(b,b)]]
。
总的来说,我们想要一个类型为的函数:
([(a,a)] -> [(b,b)]) -> [[(a,a)]] -> [[(b,b)]]
这可以简化为(a -> b) -> [a] -> [b]
。那么已经有一个功能可以为我们做到这一点!定期旧地图。
所以使用类型为(a -> b) -> [(a, a)] -> [(b, b)]
的旧mapTuple
我们通过以下方式得到正确的结果:
test = map (mapTuple myfunc) myTup
希望这是有道理的,如果不随意要求澄清:)
答案 1 :(得分:1)
这不是您问题的一对一答案。但是我不得不说,在Haskell中,元组不是像(a,a)
这样的类型的理想表示。元组用于对不同类型进行分组,例如(a,b)
。
您的工作基本上需要fmap
超过元组,但fmap
仅影响元组的第二项。然后,您可以从元组创建一个“新类型”,用于新的仿函数实例,其中fmap
将影响这两个项目。但是......你已经拥有了。它是[]
。那么,为什么不使用[]
代替元组呢?如果你深入了解应用类型,会引入极大的简单性?
mapNestedList :: (a -> b) -> [[[a, a]]] -> [[b, b]]
mapNestedList f = ((map f <$>) =<<)
Prelude> mapNestedList (+1) [[[1,2],[5,6],[9,19]]]
[[2,3],[6,7],[10,20]]
那么这里发生了什么?
map (+1)
的类型为Num a => [a] -> [a]
<$>
实际上是内联fmap
,(map (+1) <$>)
的类型为(Num a, Functor f) => f [a] -> f [a]
Maybe
类型或其他类型。在这种特殊情况下,我们的仿函数碰巧是另一个[]
。(=<<)
运算符,它实际上是monadic bind (>>=)
的翻转版本。 (=<<)
的类型为Monad m => (a -> m b) -> m a -> m b
。对于此类型签名,在此特定情况下,a
类型变量代表类似Num c => [[c]]
的类型,而b
代表Num c => [c]
,产生m b
解析为Num c => [[c]]
和m a
以解析为Num c => [[[c]]]
。(a -> m b)
的类型变量,我们可以使用((map (+1) <$>)
,最终类型((map (+1) <$>) =<<)
原来是(Num b, Monad m) => m (m [b]) -> m [b]
。再次......
Prelude> mapNestedList (+1) [[[1,2],[5,6],[9,19]],[[10,20],[30,40]]]
[[2,3],[6,7],[10,20],[11,21],[31,41]]