最近我开始使用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)来指定数组类型,但保持形状不变。有可能吗?
答案 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
。
你可以说的是computeP
和R.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])