[英]Deriving type of foldr (!!)
foldr :: (a->b->b)->b->[a]->b
(!!)::[c]->Int->c
由此我们得到a->b->b=[c]->Int->c
或a=[c],b=Int,b=c
。
我们得出结论,文件夹(!!)的类型为Int- Int->[[Int]]->Int
。
这是正确的吗?
WinGHCi告诉我一些不同:
Prelude> :t foldr (!!)
foldr (!!) :: Foldable t => Int -> t [Int] -> Int
文件foldr :: Foldable t => (a -> b -> b) -> b -> ta -> b
实际上在早期确实具有签名(a -> b -> b) -> b -> [a] -> b
,但是他们已经对该函数进行了泛化 ,因此它不仅适用于列表(其中t ~ []
),而且还适用于其他Foldable
类型(例如Maybe
, Sum
等)。 但是对于列表情况,没有任何变化,该函数仅适用于更多Foldable
类型。
foldr
的类型 在这种情况下,我们采用以下成分:
foldr :: (a -> b -> b) -> b -> [a] -> b
(!!) :: [c] -> Int -> c
或更详细:
foldr :: (a -> (b -> b)) -> (b -> ([a] -> b))
(!!) :: [c] -> (Int -> c)
由于(!!)
是使用foldr
作为函数的调用的参数,因此我们知道(!!) :: [c] -> (Int -> c)
函数的类型应与的参数类型匹配。 foldr
,所以(a -> b -> b)
foldr
(a -> b -> b)
。 因此,这意味着:
a -> (b -> b)
~ [c] -> (Int -> c)
--------------------
a ~ [c], b ~ c ~ Int
因此我们知道a
与[c]
是同一类型,并且b
和c
实际上都是Int
。 因此我们知道a ~ [Int]
。
因此,现在foldr (!!)
的类型是foldr
的输出类型,但是专门用于我们派生的内容,因此:
b -> ([a] -> b)
等于:
Int -> ([[Int]] -> Int)
或更详细:
Int -> [[Int]] -> Int
folr
的类型 在这种情况下,我们采用以下成分:
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
(!!) :: [c] -> Int -> c
并且我们对foldr
的第一个参数遵循相同的推理:
a -> (b -> b)
~ [c] -> (Int -> c)
--------------------
a ~ [c], b ~ c ~ Int
因此,文件foldr
的输出类型为:
Foldable t => b -> (t a -> b)
或指定我们所知道的:
Foldable t => Int -> t [Int] -> Int
这是ghci
派生的。
至于语义,该函数:
f = foldr (!!)
将Int
(索引)和Int
列表的Foldable
用作输入。 如果是列表,它将从右到左获取具有该索引的最右边列表的元素,并将该元素用作倒数第二个列表的索引。 我们一直这样做直到第一个列表,然后返回元素。
例如:
foldr (!!) 1 [] -> 1
foldr (!!) 1 [[2, 0]] -> 0
foldr (!!) 1 [[3, 5], [2, 0]] -> 3
对于t ~ Maybe
情况,如果为Nothing
,则将返回原始索引,如果为Just [1, 4, 2, 5]
Nothing
,则将返回该索引处的元素(一个Just
带有一个[Int]
对象)。 例如:
foldr (!!) 1 Nothing -> 1
foldr (!!) 3 Nothing -> 3
foldr (!!) 1 (Just [1, 4, 2, 5])-> 4
foldr (!!) 3 (Just [1, 4, 2, 5])-> 5
如评论中所述,在最近的GHC中, foldr :: Foldable t => (a -> b -> b) -> b -> ta -> b
。 当Foldable t => Int -> t [Int] -> Int
t ~ []
, Foldable t => Int -> t [Int] -> Int
简化为Int->[[Int]]->Int
,如您所愿。
有两种方法可以使GHCi打印更具体的类型。 一种是添加您期望的类型签名,并验证GHCi。
> :t foldr (!!) :: Int->[[Int]]->Int
foldr (!!) :: Int->[[Int]]->Int :: Int -> [[Int]] -> Int
另一种方法是在foldr
的普通(项)参数之前给t
赋予一个显式类型:
> :t foldr @[] (!!)
foldr @[] (!!) :: Int -> [[Int]] -> Int
这使用TypeApplications 。 语法为@
后跟类型名称。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.