查看MaybeT
:
λ: import Monad.Trans
λ: import Monad.Trans.Maybe
λ: :t MaybeT
MaybeT :: m (Maybe a) -> MaybeT m a
在MaybeT
的签名中,m
可以是任何更高级别的类型,即* -> *
吗?
我正在尝试学习Monad变形金刚,所以我很好奇为什么m
没有Monad
的约束。
答案 0 :(得分:4)
我们已经遇到的参数化类型的另一个示例是来自
Map k v
的Data.Map
。k
是地图中键的类型,v
是值的类型。这是类型参数非常有用的一个很好的例子。参数化的地图使我们能够从任何类型到任何其他类型的映射,只要键的类型是Ord
类型类的一部分。如果我们定义了一个映射类型,我们可以在 data 声明中添加一个类型类约束:data (Ord k) => Map k v = ...
但是,在Haskell中,永远不会在数据声明中添加类型类约束是一个非常强大的约定。为什么?好吧,因为我们没有受益很多,但我们最终写了更多的类约束,即使我们不需要它们。如果我们在
Ord k
的数据声明中放入或不放置Map k v
约束,我们就是必须将约束放入假设地图中的键可以被排序的函数中。但是如果我们不将约束放在数据声明中,我们就不必将(Ord k) =>
放在函数的类型声明中,而不关心是否可以对键进行排序或不。这种函数的一个示例是toList
,它只需要一个映射并将其转换为关联列表。它的类型签名是toList :: Map k a -> [(k, a)]
。如果Map k v
在其数据声明中有类型约束,则toList
的类型必须toList :: Ord k => Map k a -> [(k, a)]
,即使该功能没有按顺序对键进行任何比较。所以不要将类型约束放入 data 声明中,即使它似乎有意义,因为你必须将它们放入函数类型声明中。
我希望能回答你的问题。虽然m
中的MaybeT m a
不受约束,但隐含的假设m
是Monad
的实例。实际上,如果m
不是Monad
的实例,那么您将无法对MaybeT m a
值执行太多操作,因为大多数函数都要求m
为Monad
customUserAgent
的实例。
答案 1 :(得分:3)
在
MaybeT
的签名中,m
可以是任何更高级别的类型,即* -> *
吗?
没有
> :k MaybeT
MaybeT :: (* -> *) -> * -> *
因此,m
类型中的MaybeT m a
必须完全属于* -> *
种类,而不是任何其他种类。
例如,请注意下面的类型错误:
> :k MaybeT (State Int)
MaybeT (State Int) :: * -> *
> :k MaybeT State
Expecting one more argument to ‘State’
The first argument of ‘MaybeT’ should have kind ‘* -> *’,
but ‘State’ has kind ‘* -> * -> *’
In a type in a GHCi command: MaybeT (State)
答案 2 :(得分:2)
from multiprocessing.dummy import Pool # use threads def download(name): urlretrieve("https://en.wikipedia.org/w/api.php?" "action=query&prop=revisions&rvprop=content&format=json&" "titles=" + quote(name.encode('utf-8')), os.path.join('json', name + '.json')) pool = Pool(4) # download 4 titles concurrently for _ in pool.imap_unordered(download, mergel, chunksize=100): pass
可以是任何更高级别的类型,即m
?
它可以是任何类型的* -> *
。除此之外,原则上没有限制。
为什么
* -> *
没有m
的约束。
约束是通过使用Monad
的函数类型提供的,而不是通过MaybeT
构造函数。除非涉及GADT,否则向构造函数添加约束是没有用的(我相信 transformers 为了简单和符合标准而不使用GADT)。有关约束和数据类型声明的额外注释,请参阅this question and its answers。