2014-12-19 4 views
3

class (A a, B a) => C a where이라는 typeclass가 있다고 가정합니다. newtype을 사용하면 데이터 유형을 복제 한 후 GeneralizedNewtypeDeriving 언어 확장을 통해 인스턴스를 자동으로 파생시킬 수 있습니다 (how to write a derivable class?Handling multiple types with the same internal representation and minimal boilerplate? 참조).GeneralizedNewtypeDeriving을 통해 인스턴스를 파생 할 때 사용자 정의 인스턴스 사용

질문 : 자동 AC을 유도하기 위해 GHC를 얻을 수 있지만, C을 도출 B 우리 자신의 지정된 구현을 사용할 수 있습니까? 다음 코드 예를 들어

(여기서 A = Planet = LivesBC = Description)가 예상대로 작동하지 않습니다

{-# 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" 

내가 기다리고 있었다 무엇/ LivesDolphin 인스턴스에 대한 원한 Description의 파생에서 호출 될 수 있습니다.

분명히 다음과 같은 프로그램이 작동하지만, 명시 적으로 DescriptionDolphin 인스턴스로 하나가 필요합니다

{-# 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] 

추신을

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

그리고 GHC 불평 :

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

그것이 경우 GHC는 instance Lives Dolphin where의 부재에 대해 불평 것이 이상한 것 같다 무엇 수수께끼 것은 (첫 번째 프로그램에서) 내가 선언하지 않는 경우이다이 아니며 Dolphin의 경우 Description의 (자동) 유도에서 사용합니다.

newtype ProcessID = PID Int deriving Eq 

이것이 일은 당신이 PID==를 호출 할 때, 즉

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

처럼 보이는 인스턴스를 작성, 그것은 일반에 그것을 펼쳤다 :

답변

2

는 다음의 고려 Int을 입력 한 다음 ==을 실행합니다.

deriving instance Description Dolphin이 정확히 동일하게 수행하고 있다고 상상해보십시오. DolphineCat에 래핑 한 다음 description 메서드를 호출합니다. 당신이 원하는 무엇을 전혀하지 않습니다!

질문 : description의 정의가 항상 같은 경우 왜 클래스가되어야합니까? 왜 이렇게하는 정규 함수를 정의 할 수 없습니까?

(또는 이것은 당신이 해결하고자하는 좀 더 복잡한 문제를 단순화입니까?)

+0

는'that'에 설명 메서드를 호출 한 후 고양이에 돌고래도를 풀기 및 것은 : 발생이되면, GHC 것 'instance Lives Cat where where '를 사용하지 마십시오.그렇다면 왜이 ghc 인스턴스는 첫 번째 프로그램에서 '돌고래가 살고있는 곳'에 불만이 있을까요? – artella

+0

'질문 : 설명의 정의가 항상 같은 경우 왜 클래스가되어야합니까? 왜 이것을하는 정규 함수를 정의 할 수 없습니까? '이것은 내가 염두에 두었던 상황을 단순화 한 것입니다. 효율적으로 복잡한 유형 클래스 계층 구조를 상상하고 새로운 유형을 선언하고 모든 인스턴스를 재 선언 할 필요없이 해당 유형 클래스 계층 구조의 중간에있는 한 인스턴스의 동작 (주어진 유형의 경우)을 수정하려는 경우 하나의 인스턴스가 수정되었습니다. 이상적으로는 수정 된 인스턴스 만 선언하는 것이 좋습니다. – artella