如何从一个函数创建一个Haskell数组

5
为了缓存目的,我想创建一个数组,将函数的输入值映射到输出值。我知道我的函数只会在这个特定范围内使用,我考虑像这样做:
MyType = ... deriving (Ix)

myFunction :: MyType -> foo

myCache = createArrayFromFunction (start,end) myFunction

这是可能的,或者我只是认为“不可行”,还有其他解决方案。我需要数组,因为我需要O(1)访问成员并从开始就知道长度。


这是完全可行的(我经常这样做)。实际上,您可以定义一个 createArrayFromFunction 函数,以便您的代码能够正常工作。 - Reid Barton
2个回答

6

如果您只想创建一个缓存,那么只需使用listArraymap,只要有您所有索引的列表:

myCache :: Array MyType Foo
myCache = listArray (start,end) . map myFunction $ range (start,end)

我假设这里的MyType有一个Enum实例;如果没有,您需要其他方法来生成有效输入列表,这取决于您的类型。正如Reid Barton所指出的那样,这就是range的作用。

另一个选择是,如果您想向用户展示一个函数,可以使用以下代码:

myInternalFunc :: MyType -> Foo
myInternalFunc mt = (complex calculation) (using mt)

myFuncCache :: Array MyType Foo
myFuncCache = listArray (start,end) . map myFunction $ range (start,end)

myFunction :: MyType -> Foo
myFunction = (myFuncCache !)

那么你就不需要从你的模块中导出myInternalFunc;你可能也不需要导出myFuncCache,但我可以想象会需要它。如果你不在一个模块中,你可以将myInternalFunc放在myFuncCacheletwhere块中。一旦这样做,myFunction mt只是进行缓存查找,所以时间复杂度为O(1)。


1
使用 range(start, end) (http://haskell.org/ghc/docs/6.12.1/html/libraries/base-4.2.0.0/Data-Ix.html#v:range) 而不是 [start..end] - Reid Barton
@Reid:谢谢!我不经常使用数组。 - Antal Spector-Zabusky
原因很简单,我知道我的函数只需要大约500个特定的输入值,但计算结果需要很长时间。谢谢。 - fuz
有人能告诉我这个数组缓存是惰性计算的吗? - nont

3

如果你正在考虑使用数组,那么也可以考虑使用Vector。除了融合和强大的拼接函数之外,值得注意的一个重要区别是向量都是基于Int索引的。使用这个库,你的生成函数将会是:

generate :: Int -> (Int -> a) -> Vector a

问题是:我想要一个不是 Int 索引的东西。 - fuz
如果你有一个枚举类型,那么你使用的是“Int”索引,可以这么说。实际上,如果你的类型是“Ix”的实例,那么为了满足你的索引需求,在Vector周围制作一个包装器不应该很难。 - Thomas M. DuBuisson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接