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

参数化haskell数据类型中元组的长度,haskell,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,如果不能在类型系统中检查这一点,那就太傻了 这在哈斯克尔可能吗?怎么样 data

我想这样做:

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,如果不能在类型系统中检查这一点,那就太傻了

这在哈斯克尔可能吗?

怎么样

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:

或者使用更神奇的类型运算符、MultiparamTypeClass和FlexibleInstance,天哪

怎么样

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:

或者使用更神奇的类型运算符、MultiparamTypeClass和FlexibleInstance,天哪

没有。不可能

与您想要的最接近的替代方案如下所示:

data FooZero = Zero
data FooSucc a = Succ Int a

type Foo0 = FooZero
type Foo1 = FooSucc Foo0
type Foo2 = FooSucc Foo1
...
没有。不可能

与您想要的最接近的替代方案如下所示:

data FooZero = Zero
data FooSucc a = Succ Int a

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

使用固定长度向量代替元组。请参见f.e.

使用固定长度向量代替元组。参见f.e.

您可以执行以下操作

{-# 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是一个不安全的操作,但没有解决方法,因为列表类型不包含长度信息

你可以做如下事情

{-# 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是一个不安全的操作,但没有解决方法,因为列表类型不包含长度信息

不太正确,因为你需要x和y上的Foo构造函数。不太正确,因为你需要x和y上的Foo构造函数。这正是我想要的。请注意,下面的答案也是正确的,但这个库是对相同技术的有用封装。嗯,Vec并不像我想的那么容易使用。我如何声明foon包含长度为n的向量?类似于Vec n Integer v=>Foo n=Foo v的东西?例如,使用一元向量类型,您可以编写:data Foo where Foo::Vec n Integer->Foo n。你有小值的方便类型同义词,所以Foo N1,Foo N4等等…正是我想要的。请注意,下面的答案也是正确的,但这个库是对相同技术的有用封装。嗯,Vec并不像我想的那么容易使用。我如何声明foon包含长度为n的向量?类似于Vec n Integer v=>Foo n=Foo v的东西?例如,使用一元向量类型,您可以编写:data Foo where Foo::Vec n Integer->Foo n。您有小值的方便类型同义词,所以Foo N1、Foo N4等等。。。