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
。
正确吗?
WinGHCi告诉我一些不同的东西:
Prelude> :t foldr (!!)
foldr (!!) :: Foldable t => Int -> t [Int] -> Int
答案 0 :(得分:6)
早期的foldr :: Foldable t => (a -> b -> b) -> b -> t a -> 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)
函数的类型应与{{1}的参数类型匹配},因此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
个列表中的Foldable
作为输入。如果是列表,它将从右到左获取具有该索引的最右边列表的元素,并将该元素用作倒数第二个列表的索引。我们一直这样做直到第一个列表,然后返回元素。
例如:
Int
对于foldr (!!) 1 [] -> 1
foldr (!!) 1 [[2, 0]] -> 0
foldr (!!) 1 [[3, 5], [2, 0]] -> 3
情况,如果是t ~ Maybe
,我们将返回原始索引;如果是Nothing
,我们将返回该索引处的元素(a带有Just [1, 4, 2, 5]
对象的Just
。例如:
[Int]
答案 1 :(得分:4)
如评论中所述,在最近的GHC foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
中。如您所料,当t ~ []
时,Foldable t => Int -> t [Int] -> Int
简化为Int->[[Int]]->Int
。
有两种方法可以使GHCi打印更具体的类型。一种是添加所需的类型签名,并验证GHCi。
> :t foldr (!!) :: Int->[[Int]]->Int
foldr (!!) :: Int->[[Int]]->Int :: Int -> [[Int]] -> Int
另一种方法是在t
的常规(项)参数之前给foldr
提供一个显式类型:
> :t foldr @[] (!!)
foldr @[] (!!) :: Int -> [[Int]] -> Int
这使用TypeApplications。语法为@
,后跟类型名称。