是否有一种灵活的方法来为Haskell的类型族指定返回类型?

时间:2012-10-10 17:55:34

标签: haskell type-families repa

最近我开始使用Haskell的Repa库,它很大程度上依赖于type families和相关类型。我可以像这样定义一个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)来指定数组类型,但保持形状不变。有可能吗?

2 个答案:

答案 0 :(得分:2)

这样的事情有用吗?

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

computeP $ asArrayU <$> R.map id x

答案 1 :(得分:1)

你的例子

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

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

你可以说的是computePR.map id的组合保持相同的形状,无论形状如何。即。

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])