Haskell Functors 的类型推断
Haskell type inference for Functors
最近我一直在研究 Haskell,特别是整个函子概念。我越投入其中,就越有惊喜的感觉,它肯定会刺激我的多巴胺受体。
我遇到的问题如下。这是有效的代码,它提升了函数,然后首先将其应用于 IO 值,然后应用于列表。
replicator1 =
fmap (replicate 3)
replicator2 =
fmap (replicate 3)
main = do
replicated <- replicator1 getLine
print (replicator2 replicated)
用更简洁的方式写它是非常诱人的,即:
replicator =
fmap (replicate 3)
main = do
replicated <- replicator getLine
print (replicator replicated)
我的一部分说它在概念上是正确的,因为 replicator
应该适用于 IO 和 List 实例,但作为一种强类型语言 Haskell 不允许我这样做。我想我差不多明白为什么会这样了。
问题是:有什么办法可以更接近后一种变体吗?或者和前者一起生活好吗?
谢谢!
你的代码实际上很好,除了你 运行 到 dreaded monomorphism restriction 中,它使 Haskell 从 推断 最通用的可能类型replicator
.
本质上,随着限制,Haskell 将不会 推断 看起来不像函数的绑定的多态类型。这意味着它 必须 为 replicate
选择一个具体的仿函数,例如 []
或 IO
并且如果您尝试在两个不同的环境中使用它会导致错误上下文。
您可以通过三种方式使您的代码工作:
关闭单态限制:在模块顶部添加{-# LANGUAGE NoMonomorphismRestriction #-}
。
使replicator
看起来像一个函数:
replicator x = fmap (replicate 3) x
向您的代码添加显式类型签名
replicator :: Functor f => f a -> f [a]
replicator = fmap (replicate 3)
第三个选项是最惯用的。好的 Haskell 风格包括为所有顶级标识符添加显式类型签名。但是,了解其他两个选项对于理解正在发生的事情以及能够在 Haskell 中编写快速而肮脏的一次性脚本而不用担心类型签名很有用。
最近我一直在研究 Haskell,特别是整个函子概念。我越投入其中,就越有惊喜的感觉,它肯定会刺激我的多巴胺受体。
我遇到的问题如下。这是有效的代码,它提升了函数,然后首先将其应用于 IO 值,然后应用于列表。
replicator1 =
fmap (replicate 3)
replicator2 =
fmap (replicate 3)
main = do
replicated <- replicator1 getLine
print (replicator2 replicated)
用更简洁的方式写它是非常诱人的,即:
replicator =
fmap (replicate 3)
main = do
replicated <- replicator getLine
print (replicator replicated)
我的一部分说它在概念上是正确的,因为 replicator
应该适用于 IO 和 List 实例,但作为一种强类型语言 Haskell 不允许我这样做。我想我差不多明白为什么会这样了。
问题是:有什么办法可以更接近后一种变体吗?或者和前者一起生活好吗?
谢谢!
你的代码实际上很好,除了你 运行 到 dreaded monomorphism restriction 中,它使 Haskell 从 推断 最通用的可能类型replicator
.
本质上,随着限制,Haskell 将不会 推断 看起来不像函数的绑定的多态类型。这意味着它 必须 为 replicate
选择一个具体的仿函数,例如 []
或 IO
并且如果您尝试在两个不同的环境中使用它会导致错误上下文。
您可以通过三种方式使您的代码工作:
关闭单态限制:在模块顶部添加
{-# LANGUAGE NoMonomorphismRestriction #-}
。使
replicator
看起来像一个函数:replicator x = fmap (replicate 3) x
向您的代码添加显式类型签名
replicator :: Functor f => f a -> f [a] replicator = fmap (replicate 3)
第三个选项是最惯用的。好的 Haskell 风格包括为所有顶级标识符添加显式类型签名。但是,了解其他两个选项对于理解正在发生的事情以及能够在 Haskell 中编写快速而肮脏的一次性脚本而不用担心类型签名很有用。