2013-08-29 3 views
1

에 대한 메커니즘을 도출 제안 :이 질문에 병이 생각 아웃 것 같으면 미안하지만 하스켈에서 다음과 같은 뭔가 일관된 의미를 정의 할 수있을 것인지 궁금 하스켈

derive Num String from Int where 
    get = read 
    set = show 

derive Ord Bool from Integer where 
    get = fromEnum 
    set = toEnum 

derive (Monad, Functor) Maybe from [] where 
    get (Just x) = [x] 
    get Nothing = [ ] 
    set [x]  = Just x 
    set [ ]  = Nothing 

I 그 이유는 알 수 없으며 일부 상황에서는 상용구를 줄이는 것처럼 보이지만 실제로 구현할 수 있는지 여부는 모르겠습니다.

편집 :

내 의도는 다음과 같습니다. 첫 번째 예는 다음과 같이 바뀝니다.

instance Num String where 
    get = read :: String -> Int 
    set = show :: Int -> String 
    a + b = set $ get a + get b 
    a * b = set $ get a * get b 
    ... 
+3

'get'? '설정'? 나는 당신이 하스켈이 주장하는 것과는 아주 무관 한 것을 요구하고 있다고 생각한다. 자동 형 변환을하는 거지? 그건 좋은 생각이 아니다; 그것은 양방향 유형 공제의 이점으로부터 당신을 박탈합니다.이 공제는 몇 가지 명백한 변환 기능이 합리적으로 도입 할 수있는 것보다 훨씬 더 많은 상용구를 피합니다. - 또한 유형은 대략 동형이 아니기 때문에 특히 나쁜 예입니다. ''int ','set (-1) :: Bool' 또는''Set [1,2,3] :: Maybe Int'와 같은 문제로 무엇을 할 것입니까? – leftaroundabout

+0

컴파일 타임에 선언을 간단한 인스턴스 선언으로 대체 할 수 있어야한다고 생각합니다. 따라서이 제안은 하스켈의 파생 메커니즘과 상당히 관련이 없지만 형식 시스템은 변경되지 않아야합니다. 아마도 이름 변경이 순서에 있습니다. – user1502040

+0

대체 할 선언은 무엇입니까? 어떻게 사용하고 싶은지를 보여 줄 수 있습니까? – leftaroundabout

답변

4

여기에서 설명한 것은 본질적으로 동형을 기준으로 클래스 인스턴스를 정의하는 것입니다. 이것은 getset 함수를 정의하여 분명히 달성 할 수 있지만 좀 더 명확하게하기 위해 tofro이라고 부르기로합니다.

toSI :: String -> Integer 
fromSI :: Integer -> String 

instance Num String where 
    a + b = fromSI $ (toSI a) + (toSI b) 
    abs = fromSI . abs . toSI 
    ... 

실제로 쓸 수있는 아주 쉽게 정의하고주의 깊게 글로벌 typeclass을 오염시키지하기 위해 많은 규칙을 따라야합니다, 자동으로 (to, fro) 이상 하지만이 시스템을 클래스의 인스턴스를 올려 상용구를 줄이기위한 몇 가지 값이있을 수 있습니다 정크가있는 인스턴스 공간.

특히, 우리는 동형을 형성하도록 (to, fro)을 요청할 수 있습니다. 즉, 왕복 왕복 은 두 방향 모두입니다. 다른 말로 표현하자면 어떤 정수라도 주어진 n이라는 것을 의미한다면 어떤 수단으로도 을 n과 구별 할 수 없어야합니다. (물론 계산 속도 같은 것은 무시됩니다). 또한 에 대한 동일한 속성이 있어야합니다. 문자열 s : toSI (froSI s)은 과 구별 할 수 있어야합니다.

두 번째 질문은 분명히 실패합니다. "I am not a number!"은 왕복 여행에서 오류를 발생시킵니다. 순수한 코드에서 오류를 던지는 것이 위험하고, 코드가 가져 오는 사람의 코드를 위험에 빠뜨리고 오염시키는 typeclasses를 가진 많은 이유가 있습니다.

모든 문자열이 유효한 숫자가 아니기 때문에 이것이 유일한 원인이라고 지적 할 수 있습니다. fromSI . toSI은 항상 문제가있는 것 같지만 toSI . fromSI해야합니다. 예를 들어 instance Num String을 인스턴스화하는 것과 같은 작업에만 영향을 미치고 대신 (toSI, froSI) 쌍을 사용하여 Integer에 대해 instance을 얻는다면 String은 좋은 위치에있을 것입니다. 아마도.

사용해보기. String는 우리가 우리가

(1 <> 2) <> 3 == 123 
1 <> (2 <> 3) == 123 
(0 <> 1) <> 1 == 11 
0 <> (1 <> 1) == 11 

처럼 "정수을 연결"우리가주의 인 경우 "" -> 0를 정의하는 대신 만들어주는 mappend = toSI . mappend . fromSI 통해 mappend을 구현하는 경우이

instance Monoid [a] where  -- if a ~ Char then this is String 
    mempty = [] 
    mappend as bs = as ++ bs 

처럼 보이는 Monoid의 인스턴스 그러면 우리는 유용한 mempty을 얻을 수 있습니다.

mempty = toSI mempty 

잘 작동해야하는 것처럼 보입니다. 실제로 MonoidIntegerString (이유는 내가 이 아니라 Int이 아닌 이유를 생각해보십시오.)와 함께 "단방향 동형 이성"으로부터 계승되었습니다. 더 구체적으로는 Monoid typeclass에있는 함수를 사용하여 작성한 테스트를 통해 에서 toSI (fromSI n)을 구별 할 수 없으므로이 매핑을 수행하는 데 "충분 함"입니다.

하지만 다른 문제가 발생합니다. Integer에는 이미 Monoid 인스턴스가 있습니다. 이미 약 10 그들, 그래서 우리는 정식 모노 이드에 대한 예를 typeclass로 이러한 경우 중 하나를 선택하여 정보를 많이 잃고있어 가장 인기있는 존재의 곱셈과 또한

instance Monoid Integer   instance Monoid Integer 
    mempty = 0      mempty = 1 
    mappend = (+)      mappend = (*) 

있습니다. IntegerString과 함께 "일방적 인 동형 이성"(a.k.a. "retract")을 통해 Monoid이되지만 덧셈을 통해 스트립 핑을 통해 또한 곱하기가있는 스트립 핑을 통해 더 정확하게 표현됩니다.

정말 우리는 Monoid 패키지이 Integer 단지의 Addition 속성을 사용하는 전문되었음을 나타냅니다 SumProduct 같은 것들을 정의하는 이유 주위에 그 정보를 유지하려는.

그리고 그 날이 끝날 무렵에는 동형 이상의 인스턴스에 대해 타입 클래스 인스턴스를 들어 올리는 것과 정확히 같은 문제가 있습니다. 일반적으로 유형에는 동형과 수축이 많이 포함되어있어 이러한 방식으로 학대를받을 수 있으며 실제로 표준적이고 법을 준수하는 인스턴스를 갖는 것은 어렵습니다. 당신이 그것을 발견 할 때, 동형 화를 사용하여 결국 그렇게하더라도, 명시 적으로 코드 세금을 쓸 가치가 있습니다.

당신이 newtype 같은 악기를 가지고 표준 선택과 신속 Control.Newtype package 밖으로 일반적인 GeneralizedNewtypeDeriving 확장에서 그냥 "아래의"newtype 계층의 모든 방법 또는 직접 Iso, au and auf 영감을 무엇에 액세스하기위한 라이브러리의 회전이없는 및 전체 Wrapped, ala, alaflens의 메커니즘.

기본적으로이 기계는 다양한 동형 이형성, 특히 newtype에 의해 유도 된 인스턴스에 대해 풍부한 이야기를하기에 적합합니다.

관련 문제