通过GeneralizedNewtypeDeriving获取实例时使用自定义实例 [英] Using custom instance when deriving an instance via GeneralizedNewtypeDeriving

查看:122
本文介绍了通过GeneralizedNewtypeDeriving获取实例时使用自定义实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有一个类型类 class(A a,B a)=> C a where 。使用 newtype 将允许我们克隆一个数据类型,然后通过 GeneralizedNewtypeDeriving 语言
自动派生实例扩展(请参阅如何编写衍生类?处理具有相同内部表示和最小样板的多种类型?)。



问题:是否可以将ghc自动派生 A C ,但要使用我们自己指定的 B 在派生 C ?



例如下面的代码(其中 A = Planet , B = 生活
$ b $ C = 说明) b

  { - #LANGUAGE GeneralizedNewtypeDeriving# - } 
{ - #LANGUAGE StandaloneDeriving# - }
module Main(main)where

数据Cat = Cat字符串
newtype Dolphin =海豚猫派生(Planet)

---------------------------- --------------------

class Planet a where
planet :: a - >字符串

类生活在哪里
lives :: a - > String

class(Planet a,Lives a)=>说明a where
description :: a - >字符串

----------------------------------------- -------

实例行星猫其中
planet _ =生活在地球上,

实例猫生活在
的地方_ =生活在陆地上

实例说明Cat where
description a =(planet a)++(lives a)

------ ------------------------------------------

实例生活海豚在哪里
生活_ =生活在海中

- 下面的派生将使用
的实例 - 上面的海豚的生活
导出实例说明Dolphin

---------------------------------- --------------

main = do
print $ description(Cattest)
- > 生活在地球上,生活在陆地上
- OK
print $ description(Dolphin(Cattest))
- > 生活在地球上,生活在土地上
- 不行。想要生活在地球上,生活在海中

我期待/想要的是在的派生中调用 生命的实例>描述

很明显,下面的程序是可行的,但它需要为 Dolphin明确实例化描述

  { - #LANGUAGE GeneralizedNewtypeDeriving# - } 
{ - #LANGUAGE StandaloneDeriving# - }
模块Main(main)其中

数据Cat = Cat String
newtype Dolphin = Dolphin Cat派生(Planet)

---- --------------------------------------------

class Planet a where
planet :: a - >字符串

类生活在哪里
lives :: a - > String

class(Planet a,Lives a)=>说明a where
description :: a - >字符串

----------------------------------------- -------

实例行星猫其中
planet _ =生活在地球上,

实例猫生活在
的地方_ =生活在陆地上

实例说明Cat where
description a =(planet a)++(lives a)

------ ------------------------------------------

实例生活海豚在哪里
住_ =住在海中

实例描述海豚其中
描述a =(行星a)++(生命a)

---------------------------------------------- -

main = do
print $ description(Cattest)
- > 生活在地球上,生活在陆地上
- [OK]
print $ description(Dolphin(Cattest))
- > 生活在地球上,生活在海中
- [OK]

p。令人费解的是,如果(在第一个程序中)我没有声明:

  instance实例Dolphin where 
lives _ =生活在海中

然后ghc抱怨:

  Main.hs:36:1:
实例声明的超类产生的(Lives Dolphin)
的实例
在'Description Dolphin'的实例声明中,$ g $

似乎奇怪ghc会抱怨缺少 instance生动Dolphin其中如果它是不是,在的描述的(自动)派生中使用它 Dolphin

解决方案

考虑以下几点:
$ b

  newtype ProcessID = PID Int派生方程式

这样做是写一个实例,看起来像

 实例Eq PID其中
(PID x) ==(PID y) = x == y

换句话说,当您调用 == 放在 PID 中,它将它解开为一个普通的 Int ,然后执行<$ c

我想象了派生实例描述Dolphin 做的完全一样;将 Dolphine 解开为 Cat ,然后调用 description >方法。这不是你想要的!



问题:如果 description 的定义总是相同的,为什么它需要成为一个班级呢?为什么你不能定义一个正则函数来做到这一点?



(或者这是对你想解决的一些更复杂问题的简化?)


Suppose that we have a typeclass class (A a, B a) => C a where. Using newtype will allow us to clone a data type and then automatically derive the instances via the GeneralizedNewtypeDeriving language extension (See how to write a derivable class? and Handling multiple types with the same internal representation and minimal boilerplate?).

QUESTION : Is it possible to get ghc to automatically derive A and C, but to use our own specified implementation of B in deriving C?

For example the following code (where A = Planet, B = Lives, C = Description) does not work as expected :

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
module Main (main) where

data Cat = Cat String
newtype Dolphin = Dolphin Cat deriving (Planet)

------------------------------------------------

class Planet a where
  planet :: a -> String

class Lives a where
  lives :: a -> String

class (Planet a, Lives a) => Description a where
  description :: a -> String

------------------------------------------------

instance Planet Cat where
  planet _ = "lives on planet earth,"

instance Lives Cat where
  lives _ = "lives on land"

instance Description Cat where
  description a = (planet a) ++ (lives a)

------------------------------------------------

instance Lives Dolphin where
  lives _ = "lives in the sea"

--want the following derivation to use the instance of 
--"Lives" for "Dolphin" above
deriving instance Description Dolphin

------------------------------------------------

main = do
  print $ description (Cat "test")
  -- > "lives on planet earth,lives on land"
  -- OK
  print $ description (Dolphin (Cat "test"))
  -- > "lives on planet earth,lives on land"
  -- NOT OK. Want "lives on planet earth,lives in the sea"

What I was expecting/wanted was for the Dolphin instance of Lives to be invoked in the derivation of Description.

Obviously the following program works, but it requires one to explicitly instantiate Description for Dolphin :

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
module Main (main) where

data Cat = Cat String
newtype Dolphin = Dolphin Cat deriving (Planet)

------------------------------------------------

class Planet a where
  planet :: a -> String

class Lives a where
  lives :: a -> String

class (Planet a, Lives a) => Description a where
  description :: a -> String

------------------------------------------------

instance Planet Cat where
  planet _ = "lives on planet earth,"

instance Lives Cat where
  lives _ = "lives on land"

instance Description Cat where
  description a = (planet a) ++ (lives a)

------------------------------------------------

instance Lives Dolphin where
  lives _ = "lives in the sea"

instance Description Dolphin where
  description a = (planet a) ++ (lives a)

------------------------------------------------

main = do
  print $ description (Cat "test")
  -- > "lives on planet earth,lives on land"
  --[OK]
  print $ description (Dolphin (Cat "test"))
  -- > "lives on planet earth,lives in the sea"
  --[OK]

p.s. What is puzzling is that if (in the first program) I do not declare :

instance Lives Dolphin where
  lives _ = "lives in the sea"

Then ghc complains :

Main.hs:36:1:
    No instance for (Lives Dolphin)
      arising from the superclasses of an instance declaration
    In the instance declaration for ‘Description Dolphin’

Seems strange that ghc would complain about the absence of instance Lives Dolphin where if it is not using it in the (automatic) derivation of Description for Dolphin.

解决方案

Consider the following:

newtype ProcessID = PID Int deriving Eq

What this does is write an instances that looks like

instance Eq PID where
  (PID x) == (PID y)    =    x == y

In other words, when you call == on a PID, it unwraps it into an ordinary Int, and then executes == on that.

I imagine the deriving instance Description Dolphin is doing exactly the same; unwrapping a Dolphine into a Cat, and then calling the description method on that. Which isn't what you want at all!

Question: If the definition of description is always the same, why does it need to be a class at all? Why can't you just define a regular function that does this?

(Or is this a simplification of some more complicated problem you want to solve?)

这篇关于通过GeneralizedNewtypeDeriving获取实例时使用自定义实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆