2010-10-17 114 views
5

为了缓存的目的,我想创建一个数组,它将函数的输入值映射为输出值。我知道,我的功能将在这一特定范围内只用,我想是这样的:如何从一个函数创建一个Haskell数组

MyType = ... deriving (Ix) 

myFunction :: MyType -> foo 

myCache = createArrayFromFunction (start,end) myFunction 

这是可能的,或者我只是觉得“不实用”,并有另一种解决方案。我需要数组,因为我需要O(1)访问成员并从头开始知道长度。

+0

这是完全有效的(我经常这样做)。事实上,你可以定义一个'createArrayFromFunction'函数,这样你的代码就可以工作。 – 2010-10-17 14:13:34

回答

6

如果你只是想创建一个高速缓存,那么你可以只用listArraymap,只要你把所有的索引列表:

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

我认为MyTypeEnum实例这里;如果没有,您需要一些其他方式来生成有效输入列表,这取决于您的类型。正如里德巴顿指出的那样,这就是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置于let - 或where - myFuncCache之内。一旦你这样做,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]'。 – 2010-10-17 14:11:43

+0

@Reid:谢谢!我不使用阵列太多。 – 2010-10-17 14:56:28

+0

原因是我知道我的函数只有500个特定的输入值,但计算结果需要很长时间。谢谢。 – fuz 2010-10-18 06:27:26

3

如果您正在查看阵列,那么也请考虑Vector。除了融合和强大的拼接功能,值得注意的一个重要区别是矢量都是Int索引。使用这个库你的世代功能是:

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

问题是:我想要一些不是Int索引的东西。 – fuz 2010-10-20 04:10:20

+0

如果你有一个Enum,那么你正在使用IS'Int'以一种说话的方式进行索引。事实上,如果你的类型是'Ix'的一个实例,那么为你的索引需要制作一个Vector的wrapper应该不难。 – 2010-10-20 04:16:45