Haskell List Comprehension 和 List Monad
Haskell List Comprehension and List Monad
我正在尝试编写一些自定义类型 Martix a
,它基本上是列表的列表 [[a]]
。当我尝试实现一个名为 colAt
的函数时,它应该给出矩阵的垂直元素,我首先使用了列表理解:
colAt :: Int -> Matrix a -> [a]
colAt c m = [ e | r <- m, e <- r !! c ]
但是 Ghci 告诉我
Occurs check: cannot construct the infinite type: a ~ [a]
In the expression: r !! c
虽然 do 符号与
完美配合
colAt :: Int -> Matrix a -> [a]
colAt c m = do
r <- m
return (r !! c)
是什么导致了这个错误?我认为基本上列表理解是列表做符号的语法糖,但鉴于这个错误我的理解是错误的?
如果你写 e <- r !! c
,它期望 r !! c
是一个列表,因为你正在枚举该列表,但是 r !! c
是一个项目(类型 a
), 因此只有当你使用 Matrix [a]
.
时才有效
这里不用列举,可以把r !! c
移到“yield”部分:
colAt :: Int -> Matrix a -> [a]
colAt c m = [ <b>r !! c</b> | r <- m ]
但是你在这里做的是一个映射,所以你可以使用 map :: (a -> b) -> [a] -> [b]
:
colAt :: Int -> Matrix a -> [a]
colAt c = <b>map</b> (!! c)
您的理解是完全正确的:列表理解确实只是 do
表示法的语法糖!问题是您没有正确地对列表理解进行脱糖处理。
首先,让我们重复列表推导以供参考:
colAt :: Int -> Matrix a -> [a]
colAt c m = [ e | r <- m, e <- r !! c ]
现在,我将对其进行部分脱糖,以将 r <- m
位移出理解范围:
colAt :: Int -> Matrix a -> [a]
colAt c m = do
r <- m
[e | e <- r !! c]
完全脱糖很简单:
colAt :: Int -> Matrix a -> [a]
colAt c m = do
r <- m
e <- r !! c
e
与正确的实现比较:
colAt :: Int -> Matrix a -> [a]
colAt c m = do
r <- m
return (r !! c)
这里的问题现在很明显了。在正确的实现中,采用 m
,然后依次为每个项目 r <- m
,找到元素 r !! c :: a
,将其包装在列表中,然后 returns。相比之下,您的实现正确提取了每个项目 r <- m
,但随后尝试提取“列表”r !! c :: a
的每个“元素”——实际上不一定是列表,给出了您看到的类型错误.修复很简单:在正确的实现中,只需添加一个 return
,给出 [ e | r <- m, e <- return (r !! c) ]
。或者,更简单地说,利用 [x | x <- return l]
与 [l]
相同的事实,您可以更简单地将其重写为 [ r !! c | r <- m ]
.
我正在尝试编写一些自定义类型 Martix a
,它基本上是列表的列表 [[a]]
。当我尝试实现一个名为 colAt
的函数时,它应该给出矩阵的垂直元素,我首先使用了列表理解:
colAt :: Int -> Matrix a -> [a]
colAt c m = [ e | r <- m, e <- r !! c ]
但是 Ghci 告诉我
Occurs check: cannot construct the infinite type: a ~ [a]
In the expression: r !! c
虽然 do 符号与
完美配合colAt :: Int -> Matrix a -> [a]
colAt c m = do
r <- m
return (r !! c)
是什么导致了这个错误?我认为基本上列表理解是列表做符号的语法糖,但鉴于这个错误我的理解是错误的?
如果你写 e <- r !! c
,它期望 r !! c
是一个列表,因为你正在枚举该列表,但是 r !! c
是一个项目(类型 a
), 因此只有当你使用 Matrix [a]
.
这里不用列举,可以把r !! c
移到“yield”部分:
colAt :: Int -> Matrix a -> [a]
colAt c m = [ <b>r !! c</b> | r <- m ]
但是你在这里做的是一个映射,所以你可以使用 map :: (a -> b) -> [a] -> [b]
:
colAt :: Int -> Matrix a -> [a]
colAt c = <b>map</b> (!! c)
您的理解是完全正确的:列表理解确实只是 do
表示法的语法糖!问题是您没有正确地对列表理解进行脱糖处理。
首先,让我们重复列表推导以供参考:
colAt :: Int -> Matrix a -> [a]
colAt c m = [ e | r <- m, e <- r !! c ]
现在,我将对其进行部分脱糖,以将 r <- m
位移出理解范围:
colAt :: Int -> Matrix a -> [a]
colAt c m = do
r <- m
[e | e <- r !! c]
完全脱糖很简单:
colAt :: Int -> Matrix a -> [a]
colAt c m = do
r <- m
e <- r !! c
e
与正确的实现比较:
colAt :: Int -> Matrix a -> [a]
colAt c m = do
r <- m
return (r !! c)
这里的问题现在很明显了。在正确的实现中,采用 m
,然后依次为每个项目 r <- m
,找到元素 r !! c :: a
,将其包装在列表中,然后 returns。相比之下,您的实现正确提取了每个项目 r <- m
,但随后尝试提取“列表”r !! c :: a
的每个“元素”——实际上不一定是列表,给出了您看到的类型错误.修复很简单:在正确的实现中,只需添加一个 return
,给出 [ e | r <- m, e <- return (r !! c) ]
。或者,更简单地说,利用 [x | x <- return l]
与 [l]
相同的事实,您可以更简单地将其重写为 [ r !! c | r <- m ]
.