3

最近我开始使用 Haskell 的 Repa 库,它严重依赖于类型族和相关类型。我可以像这样定义一个 Repa 数组:

ghci> let x = fromListUnboxed (Z :. (5 :: Int) :. (2 :: Int)) [1..10]

并像这样操作它:

ghci> computeP $ R.map id x :: IO (Array U DIM2 Double)
AUnboxed ((Z :. 5) :. 2) (fromList [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0])

其中 U 是一个关联的数据类型,它将导致结果被表示为一个未装箱的数组;DIM2 是数组维度。我不喜欢我必须指定一个具体的尺寸,即使它可以被推断出来。相反,我想写这样的东西:

ghci> computeP $ R.map id x :: Shape sh => IO (Array U sh Double)

这是无效的,但我的意图是能够通过传递适当的关联数据类型(本例中为 U)来指定数组类型,但保持形状不变。这样的事情可能吗?

4

2 回答 2

2

这样的事情有用吗?

asArrayU :: Array U sh a -> Array U sh a
asArrayU = id

computeP $ asArrayU <$> R.map id x
于 2012-10-10T18:04:51.020 回答
1

你的例子

ghci> computeP $ R.map id x :: Shape sh => IO (Array U sh Double)

不起作用,因为在这里您声明结果值是多态的并且可以具有任何可能的 shape,但这显然是不正确的,因为x具有特定的形状,因此结果只能具有相同的特定形状,即DIM2.

你可以说的是,组合computePR.map id保持相同的形状,不管原来的形状是什么。IE

ghci> (computeP . R.map id :: Shape sh => Array U sh Double -> IO (Array U sh Double)) x
AUnboxed ((Z :. 5) :. 2) (fromList [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0])

这里重要的部分是我们将表示锁定为未装箱的值,因为这是编译器无法自动确定的部分。

但是,如果不了解更多关于您的真实用例的信息,就很难说从语法上表达您想要什么的最佳选择是什么。您是否主要对在 GHCi 中测试东西而不指定显式类型感兴趣,或者您是否想避免在实际程序中的某处显式键入?

例如,您可以定义类似

computeMap :: (Unbox a, Unbox b, Shape sh) => (a -> b) -> Array U sh a -> IO (Array U sh b)
computeMap f = computeP . R.map f

然后你可以说

ghci> computeMap id x
AUnboxed ((Z :. 5) :. 2) (fromList [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0])
于 2012-10-11T09:02:41.267 回答