그래서 여기 거래의 유형 수준의 길이 주석
사용. Haskell에는 type-level natural numbers이 있고 "팬텀 유형"을 사용하는 유형으로 주석을 달 수 있습니다. 당신이 그것을 할 그러나, 종류는 다음과 같이 표시됩니다
data Z
data S n
data LAList x len = LAList [x] -- length-annotated list
는 그런 다음 편의를 위해 일부 건설 기능을 추가 할 수 있습니다
lalist1 :: x -> LAList x (S Z)
lalist1 x = LAList [x]
lalist2 :: x -> x -> LAList x (S (S Z))
lalist2 x y = LAList [x, y]
-- ...
을 그리고 당신이있어 더 일반적인 방법 :
(~:) :: x -> LAList x n -> LAList x (S n)
x ~: LAList xs = LAList (x : xs)
infixr 5 ~:
nil :: LAList x Z
nil = LAList []
lahead :: LAList x (S n) -> x
lahead (LAList xs) = head xs
latail :: LAList x (S n) -> LAList x n
latail (LAList xs) = tail xs
자체적으로 List 정의에는 이 없기 때문에 복잡합니다. 다소 다른 접근법에 대해서도 Data.FixedList 패키지에 관심이있을 수 있습니다. 기본적으로 모든 접근법은 생성자가없는 일부 데이터 유형으로 약간 이상하게 보일 수도 있지만 조금 지나면 정상으로 보입니다. lalist1
의 모든 것을, lalist2
운영자는 위의
class FixedLength t where
la :: t x -> LAList x n
로 대체 할 수 있도록
당신 은도 typeclass을 얻을 수있을 수 있지만 당신은 아마,이 작업을 수행 할 -XTypeSynonymInstances
플래그가 필요합니다
type Pair x = (x, x)
instance FixedLength Pair where
la :: Pair x -> LAList [x] (S (S Z))
la (a, b) = LAList [a, b]
(당신이 (a, b)
에서 Pair a
에 갈 때 일종의 불일치의)처럼 뭔가를 할 수 있습니다.
-- this may change if you change your definition of the Bunch type
features :: Entity -> [Feature]
features = fst
-- we also assume a runBunch :: [Entity] -> Something function
-- that you're trying to run on this Bunch.
allTheSame :: (Eq x) => [x] -> Bool
allTheSame (x : xs) = all (x ==) xs
allTheSame [] = True
permissiveBunch :: [Entity] -> Maybe Something
permissiveBunch es
| allTheSame (map (length . features) es) = Just (runBunch es)
| otherwise = Nothing
strictBunch :: [Entity] -> Something
strictBunch es
| allTheSame (map (length . features) es) = runBunch es
| otherwise = error ("runBunch requires all feature lists to be the same length; saw instead " ++ show (map (length . features) es))
다음 당신에게 runBunch
그냥 가정 할 수 있습니다 :
당신은 아주 쉽게 다른 접근 방식을 취하고 런타임 오류로이 모든 것을 캡슐화으로 또는 명시 적으로 코드에서 오류를 모델링 할 수 있습니다 확인 런타임을 사용
모든 길이가 같고 위에서 명시 적으로 확인되었습니다. 서로 옆에있는 기능을 쌍으로 연결해야하는 경우, 예를 들어 서막에서 zip :: [a] -> [b] -> [(a, b)]
기능과 함께 패턴 매칭 괴물을 둘러 볼 수 있습니다. (여기서 목표는 runBunch' (x:xs) (y:ys)
과 runBunch' [] []
에 대한 패턴 매칭 때문에 알고리즘에서 오류가 될 것이지만, 하스켈은 당신이 매치에서 고려하지 않은 2 가지 패턴이 있다고 경고합니다.) 튜플과 법인이 끝난 매개 변수화 만들기 포함 형 클래스 둘 사이의 타협이다 (하지만 꽤 좋은 하스켈 코드를 만들어 그것을 할 수
마지막으로 방법) 모든 기능을 사용
:
type Entity x = (x, Body)
을
class ZippableFeatures z where
fzip :: z -> z -> [(Feature, Feature)]
instance ZippableFeatures() where
fzip()() = []
instance ZippableFeatures Feature where
fzip f1 f2 = [(f1, f2)]
instance ZippableFeatures (Feature, Feature) where
fzip (a1, a2) (b1, b2) = [(a1, b1), (a2, b2)]
그런 다음 당신은 당신의 기능 목록에 대한 튜플을 사용할 수 있습니다 : 서로 다른 길이의 다른 엔티티를 압축 할 수있는 기능을 포함
다음 , 최대 튜플 길이 (내 GHC에서 15)보다 커지지 않는 한. 물론 그보다 더 커지면 자신 만의 데이터 유형을 정의 할 수는 있지만 유형이 주석으로 지정된 목록처럼 일반적이지는 않습니다.
이렇게하면 runBunch
에 대한 유형 서명은 단순히 모양을 : 당신은 당신이 통합 할 수없는 컴파일러 오류를 얻을 수 있습니다 기능의 잘못된 번호 일에 그것을 실행하면
runBunch :: (ZippableFeatures z) => [Entity z] -> Something
(a, b, c)가있는 유형 (a, b).
'엔터티'의 '기능'수가 컴파일 타임에 알려져 있습니까? 어쨌든, 그것은 [의존형] (https://www.fpcomplete.com/user/konn/prove-your-haskell-for-great-safety/dependent-types-in-haskell)과 비슷하게 들린다. 그 주제에 너무 익숙하지 않아요. – Zeta