参数化haskell数据类型中元组的长度

时间:2012-02-13 16:42:59

标签: haskell

我想这样做:

data Foo n = Foo $(tuple n Integer)

因此允许

x :: Foo 3
x = Foo (1, 2, 3)

y :: Foo 5
y = Foo (5, 4, 3, 2, 1)

目前我只是

data Foo = Foo [Integer]

可以使用,但抛弃了很多很好的编译时检查。我将制作一些不同的Foo数据对象,并且每个数据对象在其整个生命周期中都会有固定数量的foo,并且在类型系统中无法检查它会感到愚蠢。

这是否可以在haskell中使用?

4 个答案:

答案 0 :(得分:4)

使用固定长度的向量而不是元组。见f.e. http://www.haskell.org/pipermail/haskell/2005-May/015815.html

答案 1 :(得分:2)

怎么样

data IntAnd b = Int :. b
infixr 5 :.

这样你可以做到

data Foo n = Foo n

x :: Foo (IntAnd (IntAnd Int))
x = Foo (3 :. 4 :. 5)

y :: Foo (IntAnd (IntAnd (IntAnd (IntAnd Int))))
y = Foo (5 :. 4 :. 3 :. 2 :. 1)

或者,如果您想要更接近原始语法的内容,请尝试TypeFamilies

data One 
data Succ a
type Two = Succ One 
type Three = Succ Two 
type Four = Succ Three
type Five = Succ Four

class NTuple a where
  type IntTuple a

instance NTuple One where
  type IntTuple One = Int 

instance (NTuple a) => NTuple (Succ a) where
  type IntTuple (Succ a) = IntAnd (IntTuple a)

x :: Foo (IntTuple Three)
x = Foo (3 :. 4 :. 5)

y :: Foo (IntTuple Five)
y = Foo (5 :. 4 :. 3 :. 2 :. 1)

或者更加神奇(TypeOperatorsMultiParamTypeClassesFlexibleInstance,哦,我的!):

data a :. b = a :. b
infixr 5 :.

class NTuple a b where
  type HomoTuple a b

instance NTuple One b where
  type HomoTuple One b = b

instance (NTuple a b) => NTuple (Succ a) b where
  type HomoTuple (Succ a) b = b :. HomoTuple a b

x :: Foo (HomoTuple Three Int)
x = Foo ( 3 :. 4 :. 5 )

y :: Foo (HomoTuple Five Int)
y = Foo ( 1 :. 2 :. 3 :. 4 :. 5 )

答案 2 :(得分:1)

不。不可能。

最接近替代你想要的东西看起来像这样:

data FooZero = Zero
data FooSucc a = Succ Int a

type Foo0 = FooZero
type Foo1 = FooSucc Foo0
type Foo2 = FooSucc Foo1
...

答案 3 :(得分:1)

您可以执行类似

的操作
{-# LANGUAGE OverlappingInstances #-}

data Foo a = Foo Int a

single :: Int -> Foo ()
single n = Foo n ()  

append :: Int -> Foo a -> Foo (Foo a)
append n foo = Foo n foo

size foo = subtract 1 $ fold (const (+1)) 0 foo
asList foo = reverse $ fold (flip (:)) [] foo

class FooOp a where
  fold :: (b -> Int -> b) -> b -> a -> b
  fooMap :: (Int -> Int) -> a -> a
  fromList :: [Int] -> a

instance FooOp (Foo ()) where  
  fold op m (Foo n ()) = m `op` n
  fooMap op (Foo n ()) = single (op n)
  fromList [x] = single x 

instance FooOp n => FooOp (Foo n) where
  fold op m (Foo n foo) = fold op (m `op` n) foo
  fooMap op (Foo n foo) = Foo (op n) $ fooMap op foo  
  fromList (x:xs) = Foo x $ fromList xs

请注意,fromList是一种不安全的操作(但没有办法,因为列表类型不包含长度信息)。