我一直在使用Applicative
实例来弄清楚它们是如何工作的。但是,老实说,我不理解这种行为。
如果我定义了自己的数据类型,则在不使用其他参数的情况下将pure
应用于该数据类型,则不会输出任何内容,但是如果我尝试对结果应用某些内容,则会出错。
ghci> data T = A
ghci> pure A
ghci> pure A 0
<interactive>:21:1:
No instance for (Show T) arising from a use of ‘print’
In a stmt of an interactive GHCi command: print it
但是,如果我将
T
设置为Show
的实例,则在两种情况下都将A
打印出来。ghci> data T = A deriving (Show)
ghci> pure A
A
ghci> pure A 0
A
我真正不明白的是
pure A
如何成为在两种情况下以不同方式打印的值。 pure A
不被部分应用吗?我确实理解了为什么在第一个示例中调用
pure A 0
错误,而在第二个示例中不调用((->) r)
错误,这对我来说很有意义。那是使用Applicative
的A
实例,因此它只是产生一个始终返回pure
的函数。但是,当尚不知道应用程序本身的类型时,如何仅用一个值实例化ojit_code?此外,GHC如何打印此值?
最佳答案
GHCi有点特殊。特别是,当您在提示符下键入表达式时,它会尝试以两种不同的方式依次解释该表达式:
IO
操作。 由于
IO
是Applicative
,因此它将pure A
解释为IO
Action ,产生的类型为T
。它执行该操作(不执行任何操作),并且由于结果不在Show
中,因此它不会打印出任何内容。如果您将T
设置为Show
的实例,那么它将为您打印出结果。当您编写
pure A 0
时,GHCi会看到以下内容:pure :: Applicative f => a -> f a
pure A :: Applicative f => f T
并且由于将
pure A
应用于0
,对于某些类型pure A
和a->b
,a
必须是函数b
,并且a
必须包含0
。(Num a, Applicative f) => f T ~ (a -> b)
(请注意
x ~ y
意味着x
和y
统一-可以使它们具有相同的类型。)因此,我们必须具有
f ~ ((->) a)
和T ~ b
,因此在这种情况下,GHC实际上可以推断出:pure A :: Num a => ((->) a) T
我们可以将其重写为
pure A :: Num a => a -> T
好吧,
(->) a
是Applicative
的一个实例,即“阅读器”,所以可以。当我们将pure A
应用于0
时,我们得到的类型为T
,即A
。当然,这不能解释为IO
Action ,因此,如果T
不是Show
的实例,则GHCi会提示。关于haskell - GHCi如何打印从 “pure”创建的部分应用的值?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28978857/