2011-09-17 7 views
6

하나의 단위 값을 가진 유형에 대한 클래스가 있습니다 (여기에 올바른 용어가 확실하지 않습니다.) 즉 사전 정의 된 값이있는 유형이입니까? 등 모든 Monoids, MonadPlus,"unit"클래스가 있습니까? 유용할까요?

에 대한

class Unit a where 
    unit :: a 

instance Unit() where 
    unit =() 

instance Unit (Maybe a) where 
    unit = Nothing 

... 나는 클래스의 또 다른 이름은 Default 수 있습니다 가정합니다. 이것은 나를 위해 최근에 두 번 유용했을 것입니다.

아마 납득 예 :

extract :: (Unit r)=> Reader r a -> a 
extract r = runReader r unit 

이 존재 하는가? 다른 사람들이 유용하다고 생각합니까?

답변

9

예, 아마도 유용 할 것입니다. 사실 약간의 호환되지 않는 버전이 모두 유용 할 것입니다! 어느 정도 문제입니다.

그런 클래스가 의미하는 것조차 명확하지 않습니다. 실제 사용하기가 어렵습니다. 필연적으로 기본 값의 여러 선택이있는 유형을 공격 할 것이고, 그렇지 않은 경우 즉시을 선택하십시오. 인스턴스가 제공하는 경우 클래스를 처음 사용하는 모든 이점을 거의 잃을 수 있습니다.

몇 가지 예 :

  • Monoid를 들어 경우, 당신은 분명히 신원 요소가 기본값으로 기대. 하지만 이제는 두 개 이상의 현명한 Monoid 인스턴스를 가진 많은 유형의 문제로 돌아 왔습니다. Integer 기본값은 0 또는 1입니까? Monoid의 경우 표준 라이브러리는 newtype 래퍼를 사용하지만 래핑 된 유형을 사용하는 것은 어렵습니다. Monoid과 함께 사용하면 mconcat에 액세스 할 수 있기 때문에 정상적으로 작동하지만 을 수행 할 수 없습니다. 흥미로운 점이 있습니다. 그냥 기본값으로.

  • "빈 값"이있는 Functor 유형의 경우 명백한 기본값이됩니다. 이것은 MonadPlusAlternative이 수행하는 작업이며 ... Monoid과 겹치기도합니다. 메모리가 나를 지원한다면 적어도 세 가지 인스턴스가 동일한 유형이 하나 이상 있어야합니다. 하나 이상의 선택이있을 때 어느 것을 골라야합니까? 목록을 고려하십시오 : 맹목적으로 덧붙일 수 있습니다. 임의의 것으로 Monoid을 입력하고 빈 목록을 ID로 사용합니다. Monoids 목록의 경우 zipWith mappend 일 수 있으며 repeat mempty 인 리프트 된 모노oid를 신원으로 지정할 수 있습니다. 많은 펑터는 비슷한 Monoid 인스턴스를 가지고 있지만 둘 다 항상 같은 것은 아닙니다. 따라서 목록을 선택하면 개념적으로 다른 Functor과 일치하지 않게됩니다!

  • 단위 유형이 () 인 경우 기본값을 선택하는 것이 어렵지 않습니다! 그러나 열거는 어떨까요? 첫 번째 생성자를 선택하는 것이 맞습니까? 때로는 항상 그런 것은 아닙니다. 수업을 사용하는 사람들은 어떻게 알 수 있습니까?

  • Bounded? 위의 내용 중 어느 것도 적용되지 않으면 minBound을 사용할 수 있습니다. 그러나 위의 유형 중 일부는 Bounded 일 수 있으므로 기본값이 최소값이 아닌 경우 문제를 혼동하게됩니다.

기본적으로, 이 이해하기을 보인다 충분한 중복이 ...하지만 정말, 당신은 여기에 마음에 적어도 세 가지 다른 종류의 클래스를 가지고, 그들을 통합하려고하는 것은으로 아마 아니다 도움이 처음에는 보인다.


조금 더 나은 일을 아래로 핀과 그냥 Monoid 또는 다른 기존의 클래스를 개혁하지 않고 "기본"값의 명확하고 일관성있는 의미 론적 해석, 을 줄 수있는 경우, 유형 클래스는 쉽게 그런 것을 멈추지 않고 "기본"이 선택되는 것에 대해 생각할 필요없이 사용하십시오. 그러나 나는 그것이 가능하도록 내 희망을 갖지 않을 것이다.

그렇다면 표준 유형 클래스에서 다루지 않는 분명히 합리적인 경우는 ()과 같은 싱글 톤입니다. 대개의 경우, 이것들은 대단히 유용하지 않습니다 - 분명한 이유가 있습니다 - 아마도 그러한 클래스가없는 이유 일 것입니다. 그런 클래스가있는 곳은 입니다. 그러나 타입 레벨과 텀 레벨 모두에서 단일 값을 나타 내기 때문에 유형 수준의 속임수와 관련된 작업을 할 때 유용합니다. 따라서 이러한 유형의 클래스 타입 레벨 값을 자유롭게 조작 할 수있게 해줍니다. 그런 다음 그 타입에 따라 타입을 추가 할 수 있습니다. 예를 들어 타입 레벨 값을 기반으로 타입 클래스 인스턴스를 선택할 수있는 다른 함수에 전달할 수 있습니다. 이러한 이유로, 나는

class TermProxy t where 
    term :: t 

-- This makes explicit the lexical pun of() having type(). 
instance TermProxy() where 
    term =() 

instance (TermProxy a, TermProxy b) => TermProxy (a, b) where 
    term = (term, term) 

나는 이러한 클래스는하지만, 다른 상황에서 매우 유용합니다 의심 : 예컨대, a class along those lines in my perpetually-incomplete type-hackery library 있습니다.

+0

이렇게 모호한 답변을 주셔서 감사합니다. 나는 실제로 "기본값"(아마 언급하지 말았어야했다)이라는 개념에 관심이 없지만 함수 (또는 추상화)의 왼편에서 발생하는 이러한() ...이 수업을 어떻게 사용하고 싶은지 더 생각해야합니다. 감사! – jberryman

+1

@ jberryman : 아마도 당신이 한 것은 정확히 하나의 nullary 생성자가있는 유형의 유형 클래스라고 생각합니까? '()','Nothing','[]'등을 포함합니다.,하지만 부울이나 숫자 또는 그런 건 아닙니다. 그것은 적어도 분명히 정의되어 있으며 싱글 톤만큼 혼자만의 것은 아닙니다. –

+0

예, 맞습니다. 내'Reader '예제의 행을 보면 싱크 나 함수 또는 다른 유형의 Cofunctor-ish의 경우 특수한 경우'()'에 대한 흥미로운 함수를 정의 할 수 있다는 것을 알게되었습니다. 'liftCofunc :: (Cofunctor f) => f() -> f a'입니다. 위의 함수가 더 일반적으로 정의 될 수 있는지를 보는 것이 흥미로울 것이라고 생각했습니다. 다시 한번 감사드립니다. * 편집 : * 'Cofunctor'도 표준 클래스가 아니라는 것은 우연이 아닌 것 같아요.) – jberryman

6

Default 종류의 클래스를 찾고 있습니다. "기본"이 무엇인지에 대한의 미가 논쟁의 여지가 있지만 (C.A. McCanns가 그의 귀중한 의견을 들어 줄 것을 제안합니다), data-default이라는 비교적 일반적으로 사용되는 패키지에서 Default 클래스를 얻을 수 있습니다.

클래스는 다음과 같습니다

unit :: Enum a => a 
unit = toEnum 0 

또는 경계 클래스 어쩌면 더 나은 : 새 클래스를 피하려면

-- | A class for types with a default value. 
class Default a where 
    -- | The default value for this type. 
    def :: a 
+0

고맙습니다. 나는 C.A에 댓글을 달았습니다. McCann, 이것이 "기본"이라는 생각은 일종의 생각이었습니다. 나는 잘하려고 노력해야 할 것입니다. – jberryman

+2

예, 'Default' 클래스는 일관성이 있습니다. 당신이 바라는대로. 그것은 앞서 언급 한 내재 된 혼란의 일부를 여전히 가지고 있습니다. 예를 들어, 일부 모나드 인스턴스는'return def '이고, 다른 인스턴스는 그렇지 않습니다. 그래서'(Monad m, Default m a) =>'와 같은 문맥을 가진 함수는 반드시 다른 Monad에 대해 매우 다르게 행동 할 것입니다. –

+2

'data-default'는 설정 구조체 등에서 특히 유용합니다. 즉, 애플리케이션 컨텍스트 내에서 적절한 기본값이 존재하는 경우에 유용합니다. 게다가 인스턴스는 반출되지 않습니다. –

3

, 당신은 열거 클래스의 관점에서 단위를 정의 할 수 있습니다 :

unit :: Bounded a => a 
unit = minBound 

이 두 가지 모두 유닛 유형에 대한 예상 결과를 생성합니다 (그리고 다른 단일 죄수 structor 형) : 다른 답변에서 언급 한 데이터 기본 클래스 (비교

*Main> unit ::() 
() 

단점은) 적은 경우, [A]에 대한 [] 반환 특히 어떤 인스턴스가 있다는 것입니다. 또한 결과는 특정 유형에서 기대할 수있는 결과가 아닙니다. 특히 minBound를 사용하는 경우 특히 그렇습니다.

*Main> unit :: Int 
-2147483648 

*Main> unit :: Char 
'\NUL' 

*Main> unit :: Bool 
False 
관련 문제