문제
이 코드:
type family Id obj :: *
type instance Id Box = Int
나는 그것을 만들고 싶은 그래서 나는 항상 얻을 수 있습 Int 에서의 Id 를 입력 가족입니다.인식 전환이 필요합니다.
나는 면을 만들기 클래스 작동:
class IdToInt a where
idToInt :: Id a -> Int
instance IdToInt Box where
idToInt s = s
그리고 실제로 컴파일.하지만하려고 하는데 그것을 사용:
testFunc :: Id a -> Int
testFunc x = idToInt x
나는 오류가:
src/Snowfall/Spatial.hs:29:22:
Couldn't match type `Id a0' with `Id a'
NB: `Id' is a type function, and may not be injective
In the first argument of `idToInt', namely `x'
In the expression: idToInt x
In an equation for `testFunc': testFunc x = idToInt x
그래서,어떻게 만들 수 있습니 변환 유형에 대한 가족 Id 을 얻을 Int?
에 따라 대답하여 ehird 가는 다음이지만 그것은 작동하지 않거나:
class IdStuff a where
type Id a :: *
idToInt :: Id a -> Int
instance IdStuff Box where
type Id Box = Int
idToInt s = s
testFunc :: (IdStuff a) => Id a -> Int
testFunc x = idToInt x
그것은 오류가:
src/Snowfall/Spatial.hs:45:22:
Could not deduce (Id a0 ~ Id a)
from the context (IdStuff a)
bound by the type signature for
testFunc :: IdStuff a => Id a -> Int
at src/Snowfall/Spatial.hs:45:1-22
NB: `Id' is a type function, and may not be injective
In the first argument of `idToInt', namely `x'
In the expression: idToInt x
In an equation for `testFunc': testFunc x = idToInt x
해결책
다른 사람들이 지적으로,문제는 컴파일러 알아낼 수 없습니다 a
사용합니다.데이터 가족은 하나의 솔루션이지만,대체는 때때로 쉽게 작동하는 형식을 사용하려면 증인이다.
변경 클래스
class IdToInt a where
idToInt :: a -> Id a -> Int
instance IdToInt Box where
idToInt _ s = s
-- if you use this a lot, it's sometimes useful to create type witnesses to use
box = undefined :: Box
-- you can use it like
idToInt box someId
-- or
idToInt someBox (getId someBox)
질문에 응답할 필요가 있는 어떠한어 Id
, 가 단 하나의 유형 a
그것은 나타나야 합니까?즉,거기에 하나를 하나 사이의 대응 a
s Id a
s?그렇다면,데이터 가족하는 올바른 접근 방식이다.하지 않을 경우,당신이 선호 할 수 있는 증거입니다.
다른 팁
당신은 할 수 없습니다.testFunc :: (IdToInt a) => Id a -> Int
가 필요합니다.유형 가족이 열려 있으므로 누구도
type instance Id Blah = ()
.
언제든지 전환 기능을 제공하지 않습니다.가장 좋은 방법은 유형 가족을 수업에 넣는 것입니다.
class HasId a where
type Id a
idToInt :: Id a -> Int
instance IdToInt Box where
type Id Box = Int
idToInt s = s
.
당신은 여전히 컨텍스트가 필요합니다.
할 수 없는 함수를 사용의 유형 IdToInt a => Id a -> Int
방법이 없기 때문에 어떤 종류의 결정 a
입니다.다음 예에서는 이 방법을 보여 줍니다.
type family Id a :: *
type instance Id () = Int
type instance Id Char = Int
class IdToInt a where idToInt :: Id a -> Int
instance IdToInt () where idToInt x = x + 1
instance IdToInt Char where idToInt x = x - 1
main = print $ idToInt 1
기 Id () = Id Char = Int
, 의 유형 idToInt
위의 컨텍스트 Int -> Int
, 은 다음과 같이 계산됩니다 Id () -> Int
고 Id Char -> Int
.을 기억하는 오버로드 방법을 선택에 따라 형식입니다.모두 클래스의 인스턴스가 정의 idToInt
기능이 있는 형식 Int -> Int
, 형식 검사 결정할 수 없는 한 사용합니다.
를 사용해야 합 데이터 가족을 대신의 유형이 가족,그리고 선언할 뉴스.
data family Id a :: *
newtype instance Id () = IdUnit Int
newtype instance Id Char = IdChar Int
와 뉴스 Id ()
고 Id Char
은 모두 수 있지만,그들은 다른 유형이 있습니다.의 유형 Id
알 유형 검사에는 과부하 기능을 사용합니다.