当我询问foldl类型时,我看到的是:
*Main> :t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
在这种情况下,t a
是什么?
我想这意味着该功能正在使用Foldable
参数化a
,但我甚至不确定语法。例如,为什么我不能用t a
替换Foldable a
?
而且,奖金问题,如果我必须自己定义foldl
,我会从基本案例开始
foldl f b [] = []
但是如果基本案例采用列表,那么接受Foldable
就没有多大意义了。什么是"空的可折叠"我可以用作基本情况吗?
答案 0 :(得分:6)
Foldable
被称为“类型类”。说Foldable t =>
声明t
必须实现Foldable
的要求。但是,t
仍为t
,并且不会像Java中那样折叠为对Foldable
接口的引用。这就是为什么你不能只有Foldable a
。
绝对查看https://hackage.haskell.org/package/base-4.10.1.0/docs/Data-Foldable.html,了解Foldable
的要求以及可以使用哪些方法的解释。
无论如何,如果您想使用Foldable
方法之一,那么请使用Foldable
之类的已知Set
类型:
import qualified Data.Set as S
import Data.Foldable
sumSet :: (Num n) => S.Set n -> n
sumSet ns = foldl' (\ n acc -> n + acc ) 0 ns --make this pointfree if you want
或者您可以使用类型参数并将其约束为可折叠:
sumFld :: (Num n, Foldable f) => f n -> n --different signature
sumFld ns = foldl' (\ n acc -> n + acc ) 0 ns --same implementation!
以下打印6,两次:
main :: IO ()
main = print (sumSet $ S.fromList [1, 2, 3]) >> print (sumFld $ S.fromList [1, 2, 3])
答案 1 :(得分:6)
我喜欢其他答案,它们简要讨论了类型和类之间的区别,因此以这种方式回答问题的前半部分。为了完成这个答案,我将非常简短地重申一下;但是请看其他答案以获得更长的解释,因为我想把大部分时间花在问题的后半部分。
所以:Foldable
是类型类(类型集合)。 t
类型的foldl
类型而不是类型集合,这解释了为什么它不能被Foldable
替换。
但我认为这也是一个非常有趣的问题,其他答案没有解决:
如果我必须自己定义
foldl
,我会从基本情况开始foldl f b [] = []
但是如果基本案例采用列表,那么接受
Foldable
就没有多大意义。
如果您要自己定义foldl
,则会为特定类型创建Foldable
的实例。因为在实例中您知道涉及哪种特定类型,所以您可以为 类型编写基本案例,而无需了解Foldable
的任何其他实例。在列表的Foldable
实例中:
instance Foldable [] where
foldl f b [] = b
...完全打字,因为我们知道t ~ []
。另一方面,在另一种类型的实例中,我们当然必须使用不同的基本情况。例如:
import qualified Data.Set as S
instance Foldable S.Set where
foldl f b s | S.null s = b
同样,instance
块中的是可以的,因为我们有t ~ S.Set
。我们可以(并且通常必须)编写仅适用于S.Set
的内容,并且不能与其他Foldable
实例一起使用。
答案 2 :(得分:3)
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
在这种情况下,什么是
t a
?我想这意味着该功能正在使用
Foldable
参数化a
[...]
这是完全正确的。但请注意,“{strong> Foldable
参数化a
”,而不是“Foldable
参数化a
”。正如hegel5000's answer所解释的那样,当您在Foldable t
左侧写=>
时,您正在说关于类型(构造函数)t
。用t a
替换Foldable a
有点像将名词放在名词所在的位置。
继续讨论您的红利问题:foldl
恰好是Foldable
课程的一种方法。这意味着,在为类型编写Foldable
实例时,您可以提供foldl
的适当定义,您可以在其中使用该类型的特定功能(例如[]
1}}是列表的构造函数 - 另请参阅Daniel Wagner's answer)。
如果foldl
不是Foldable
的方法,那么在实现它时,你唯一可以用来处理t a
参数的东西就是(其他)Foldable
(foldr
,foldMap
等)的方法,因为除了t
之外你不知道其他任何事情。Foldable
实例。 (也许令人惊讶的是,有可能以这种方式实现foldl
。这样的实现作为foldl
类中Foldable
方法的默认提供,因此您不需要如果你不认为有必要,你必须在编写实例时自己实现它。)
答案 3 :(得分:2)
在上下文(Foldable t) => ...
中,t
是可折叠类型。例如,列表类型为[]
。
foldl
的一些更具体的类型将是
foldl :: (b -> a -> b) -> b -> [a] -> b
foldl :: (b -> a -> b) -> b -> Tree a -> b
可以阅读 Foldable t => ...
,因为t
必须是Foldable
。应用于类型Foldable
的类型构造函数t
不是!因此,Foldable t
甚至不是一种类型,您无法在=>
的右侧使用它。