상당히 다형성 라이브러리를 작성하려고합니다. 나는 말해주는 것보다보기 쉬운 상황에 처했습니다. 그것은 조금 다음과 같습니다유형 패밀리 유형 Hackery
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
import Data.Map (Map)
import qualified Data.Map as Map
class Format f where type Target f
class Format f => Formatter x f where
target :: forall y. Formatable y => Target f -> x -> y
class Formatable y where name :: y -> String
instance Formatable Integer where name = show
instance Formatable Int where name = show
split :: forall x f. (Format f, Formatter x f) => x -> f -> String -> [Either String (Target f)]
split = undefined
display :: forall x f. (Format f, Formatter x f) => f -> String -> x -> String
display f str x = let
chunks = split x f str
built = foldr apply "" chunks
apply (Left s) accum = accum ++ s
apply (Right t) accum = accum ++ name (target t x)
in foldr apply "" chunks
는 기본적으로, 우리는 Target
s의 수를 정의 다형성 Format
들,있다. 또한 다른 형식 옵션 (여기서는 간단히 name
으로 줄임)에 응답하는 방법을 알고있는 Formattable
개체가 여러 개 있습니다.
이 Formattables
은 다양한 방법으로 구성되며 다양한 대상에 응답 할 수 있습니다. Formatter
은 본질적으로 Format
과 Formattable
사이의 라우터입니다. 특정 형식의 대상이 있으면 적절한 Formattable
개체로 응답합니다.
이것은 모두 매우 추상적입니다.
DateFormat
이Year
,Month
및Day
같은 목표를 지정 예를 들면 다음과 같습니다이다.MonthType
는 "2월"와 같은 이름을 가지고Int
의Formattable
newtype은입니다- 간단한
instance Formattable Int where name = show
DateTime
이(Int, MonthType, Int)
에 대한 타입 동의어가 될 수도있다.
는 (물론, 나는 그런 주위에 올바른 값을 배관으로, 여기에 기계를 많이 잘라했지만, 당신은 아이디어를 얻을.)
display
기능은 매우 간단하다. 형식을 지정하는 문자열, 표시 할 객체 및 형식화 문자열을 모두 문자열로 렌더링합니다.
먼저 문자열을 대상과 문자열로 나눕니다. 예를 들어, 날짜 포맷터는 "%Y-%m-%d"
문자열을 [Right Year, Left "-", Right Month, Left "-", Right Day]
으로 나눌 수 있습니다. split
함수는이를 수행하며 여기에서 수정되었습니다.
display
함수는 단순히 각 대상의 Formattable
을 추적하고 문자열을 누적합니다.
아니면 적어도, 그렇게해야합니다.
Reduced.hs:20:16:
Could not deduce (Target f ~ Target f0)
from the context (Format f, Formatter x f)
bound by the type signature for
display :: (Format f, Formatter x f) => f -> String -> x -> String
at Reduced.hs:(19,5)-(24,30)
NB: `Target' is a type function, and may not be injective
Expected type: [Either [Char] (Target f0)]
Actual type: [Either String (Target f)]
In the return type of a call of `split'
In the expression: split x f str
In an equation for `chunks': chunks = split x f str
Failed, modules loaded: none.
나는 내 인생은 왜 알아낼 수 없기 :
는 그러나 다음과 같은 오류 유형 검사를 실패합니다. 내가 도대체 뭘 잘못하고있는 겁니까?
나는 여전히 붙어 있습니다. 형식 패밀리와'Format' 클래스를 완전히 생략해도 (그리고 class :: Ord f => Formatter xf 인 target :: forall y. f -> x -> y'를 사용하면) 다음과 같이 실패합니다 : Reduced.hs : 23 : 40 : 'name'을 사용하여 발생하는 (형식 가능 y0)의 모호한 유형 변수 'y0' 가능한 수정 : 이러한 유형의 변수를 수정하는 유형 서명을 추가하십시오. '(++) ', 즉'name (target tx)'에서 다음 표현식에서 누적 ++ 이름 (대상 tx) 'apply '의 방정식에서 : 누적 값 = accum ++ name (target tx) – So8res
@ So8res 오류는 인라인 읽을 수 없지만 적어도 새로운 오류처럼 보입니다. 아마도 새로운 질문을 던지겠습니까? –
Hrm. 그것은. 내 사과. 나는'Formatable'을위한'Box' 데이터 타입을 생성함으로써 에러를 해결할 수 있습니다. 가장 우아한 솔루션은 아니지만 지금은 효과가 있습니다. – So8res