在Haskell中推导Applicative

为什么 GHC 不会派生ApplicativeKO

#!/usr/bin/env stack
-- stack --resolver lts-17.10 script

{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype KO a = KO a deriving (Functor, Applicative) -- doesn't derive Applicative

newtype OK f a = OK (f a) deriving (Functor, Applicative) -- that's ok

main :: IO ()
main = print "hello"

• 无法创建“Applicative KO”的派生实例(即使使用狡猾的 GeneralizedNewtypeDeriving):不能充分减少表示类型 • 在“KO”typecheck 的 newtype 声明中

回答

GHC 有四种创建实例的方式:

  • stock:通过模式匹配等从头开始编写每个类方法的新实现
  • newtype: 当声明一个newtype包装已经有实例的类型时,重用那个实例,在适当的时候插入和删除新类型的包装器
  • anyclass: 声明一个没有方法定义的实例(因此为每个方法使用默认实现,如果有的话)
  • via: 的概括newtype,它允许您从具有明显相同表示的任何其他类型继承实例,再次通过在适当的时刻插入/删除新类型包装器

在您的代码片段中,该stock方法用于派生,Functor因为您已打开DeriveFunctor. 但是,目前没有stock推导Applicative。该via方法仅在显式请求时触发,并且您尚未打开DeriveAnyClass,因此剩下的唯一选项是newtype,因此 GHC 尝试从包装类型继承实例。然后它遇到了麻烦,因为Applicative应该是用于容器类型的,而所包含的类型不是一种,所以它会抱怨。

这解释了您的第一个片段的FunctorvsApplicative差异。对于 的第一个和第二个片段的差异Applicative,我们只需要观察在解开第二个片段后,我们确实有一个容器类型;因此,只要它的参数有一个,你就会得到一个Applicative实例。OKf

另请参阅有关派生策略的文档。


以上是在Haskell中推导Applicative的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>