Data.Foldable显示以下代数数据类型:
data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a)
其kind
为* -> *
。它需要a
类型。
Prelude> :k Tree
Tree :: * -> *
现在让我们看看trait Foldable[_]
,一个"更高级的类型"来自Functional Programming in Scala的Scala:
trait Foldable[F[_]] {
def foldRight[A,B](as: F[A])(z: B)(f: (A,B) => B): B
...
}
优秀的书说:
就像值和函数具有类型,类型和类型构造函数一样 有种类。 Scala使用种类来跟踪一个类型的类型参数 构造函数需要,......
修改
指定trait Foldable[F[_]]
时,F[_]
是否始终指示更高级别的类型? F[_]
可能是其他什么吗?它可以是一种类型 - F[A]
吗?
答案 0 :(得分:5)
Scala中的F[_]
代表Haskell中的* -> *
:这是一种“接收”具体类型的类型(Scala中的_
和第一个*
在Haskell中)并返回一个新的具体类型(F[A]
用于某些具体类型A
和具体的“容器”F
在Scala中)。
是的,F[_]
代表某些更高级的类型,例如List[_]
或Option[_]
。在像trait Foldable[A,F[A]]
这样的scala中定义遍历是没有用的,因为我们会说Foldable
需要使用折叠的特定事物(A
)来定义。
答案 1 :(得分:3)
你没有问过很多问题,但是如果你想要一个大概的想法:是的,这两种语言的“善意”系统都是他们自己的类型系统的类型系统。 *
类型不是通配符,而是特殊类型的原子; *
是“具体类型”的类型,例如String
,[String]
和Tree String
。
反过来有[]
或Tree
(见差异?)之类的内容* -> *
;这是“单一参数化类型”的类型,它采用具体类型并产生另一种具体类型。
最后一个例子:有一些名为“monad变形金刚”的东西,如MaybeT
,它采用像IO
这样的monad,并产生另一个monad,如IO . Maybe
(如果你原谅功能的使用)组合经营者,他们通常不被录取)。那是什么类型的?为什么,(* -> *) -> * -> *
当然:monad有点* -> *
所以我们采用其中一种类型并将其转换为另一种类型。
我不能在Scala语法方面有如此多的专业知识,但在互联网上我们看到Scala中monad变换器特性的定义为:
trait MonadTrans[F[_[_], _]] {
def lift[G[_] : Monad, A](a: G[A]): F[G, A]
}
所以我认为你的猜测大多是正确的(括号表示一个依赖类型)。
拥有这些事物的类型理论可以保证您永远不会将IO IO
之类的东西写成具体类型,或MaybeT String
。
答案 2 :(得分:2)
F[_]
在该上下文中,即作为类或方法的类型参数,总是意味着更高级的类型,也就是类型构造函数。您也可以将其写为F[A]
,但通常只有在您要重复使用A
来表达约束时才会这样做,例如trait Something[F[A] <: Iterable[A]]
。
正如书中所说,这种类型限制了什么东西(类型或类型构造函数)可以放在那里。您可以拥有Foldable[List]
或Foldable[Option]
,因为这些是单参数类型构造函数,但您不能拥有Foldable[String]
或Foldable[Either]
。同样,您不能拥有Foldable[List[Int]]
,因为List[Int]
是普通类型,例如String
(即*
种类型)。并且可以具有T[A] = Either[String, A]
类型的可折叠,因为它是1参数类型,也就是1参数类型构造函数,也就是类型{{1}虽然你必须使用有点令人难以忍受的语法* -> *
来编写它。你可以看到,只有实现给定Foldable[({type T[A]=Either[String, A]})#T]
的&#34;类型&#34; (类型构造函数)foldRight
具有正确的&#34;形状&#34 ;;如果F
是F
,那么Int
会是什么?
F[A]
使用不同的scala用法表示存在类型F[_]
;尽量不要对此感到困惑,他们没有发现。