Ale*_*ing 5 haskell typeclass applicative
我一直在玩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
Run Code Online (Sandbox Code Playgroud)
但是,如果我创建T一个实例Show,则A在两种情况下都打印出来.
ghci> data T = A deriving (Show)
ghci> pure A
A
ghci> pure A 0
A
Run Code Online (Sandbox Code Playgroud)
我真正不明白的是,如何pure A在两种情况下以不同的方式打印一个值.是不是pure A部分应用?
我理解为什么pure A 0在第一个例子中调用错误而在第二个例子中调用错误 - 这对我来说是有意义的.那是使用的((->) r)实例Applicative,所以它只是产生一个总是返回的函数A.
但是pure,当应用程序本身的类型尚不为人所知时,如何仅使用一个值进行实例化?此外,GHC怎么可能打印这个值?
dfe*_*uer 14
GHCi有点奇特.特别是,当您在提示符下键入表达式时,它会尝试按两种不同的方式解释它,按顺序:
IO执行的动作.由于IOIS Applicative,它被解释pure A为一种IO类型的生成作用的东西T.它执行该操作(什么都不做),并且由于结果不存在Show,因此不会打印任何内容.如果您创建T了一个实例Show,那么它会为您打印出结果.
当你写作时pure A 0,GHCi看到了这个:
pure :: Applicative f => a -> f a
pure A :: Applicative f => f T
Run Code Online (Sandbox Code Playgroud)
而且因为你申请pure A到0,pure A必须是一个函数a->b对于某些类型的a和b,并且a必须包含0.
(Num a, Applicative f) => f T ~ (a -> b)
Run Code Online (Sandbox Code Playgroud)
(注意,这x ~ y意味着x和y统一 - 它们可以具有相同的类型.)
因此,我们必须有f ~ ((->) a)和T ~ b,所以其实GHC推断,在这种情况下,
pure A :: Num a => ((->) a) T
Run Code Online (Sandbox Code Playgroud)
我们可以改写为
pure A :: Num a => a -> T
Run Code Online (Sandbox Code Playgroud)
嗯,(->) a是一个实例Applicative,即"读者",所以这没关系.当我们申请时pure A,0我们得到一些类型T,即A.当然,这不能被解释为一个IO动作,所以如果T不是一个实例Show,GHCi会抱怨.