将返回列表的函数转换为函数列表

时间:2014-12-24 15:04:02

标签: haskell functional-programming

我有一个函数f :: Int -> [a],它总是返回一个大小为n的列表,如下所示:

f 0 = [a_0_1, a_0_2, ..., a_0_n]
f 1 = [a_1_1, a_1_2, ..., a_1_n]
.
.
.
f k = [a_k_1, a_k_2, ..., a_k_n]

我想将其转换为函数列表:

[f_1, f_2, ..., f_n] :: [Int -> a]

,其中

f_k i = a_i_k

我希望我用过的符号足够清晰,可以传达我想要的东西。

5 个答案:

答案 0 :(得分:1)

使用lambdas

fn = [(\k -> (f k)!!i) | i <- [0..n - 1]]

然后

[f1, f2, f3, ...] = fn

但你应该分析你的一般问题(这种方法很慢)。

完整的沙盒代码:

n = 5

f k = [2 * k + i | i <- [1..n]]

fn = [(\k -> (f k)!!i) | i <- [0..n - 1]]

(f1:f2:_) = fn

main = do

    print $ f 4
    print $ (fn!!3) 4
    print $ f2 4

答案 1 :(得分:1)

如果你有

f 0 = [a_0_0, a_0_1 ... a_0_m]
f 1 = [a_1_0, a_1_1 ... a_1_m]
...
f n = [a_n_0, a_n_1 ... a_n_m]

然后

matr = transpose $ map f [0..n]

给你

[ [a_0_0, a_1_0 ... a_n_0]
, [a_0_1, a_1_1 ... a_n_1]
...
, [a_0_m, a_1_m ... a_n_m]
]

您的公式为f_j i = a_i_j,其中i的范围超过[0..n]j范围超过[0..m]

matr转置后,等式变为f_j i = matr_j_i,可反映如下:

map (\j i -> matr !! j !! i) [0..]

整个功能是

transform f n = map (\j i -> matr !! j !! i) [0..] where
    matr = transpose $ map f [0..n]

或者只是

transform f n = map (!!) $ transpose $ map f [0..n]

修改

正如@josejuan指出的那样,这个代码效率不高,因为在评估

(transform f n !! j) i
所有transpose

f i'强制i' <= i

答案 2 :(得分:1)

让我们首先将函数应用于所有这些值:

listf = map f [0..k]

所以

listf = [[a_0_1, a_0_2, ..., a_0_n]
        ,[a_1_1, a_1_2, ..., a_1_n]
        ,...
        ,[a_k_1, a_k_2, ..., a_k_n]]

现在我们有一个列表清单,但这是错误的方法。所以让我们进行转置:

listft = transpose listf

listft = [[a_0_1, a_1_1, ..., a_k_1]
         ,[a_0_2, a_1_2, ..., a_k_2]
         ,...
         ,[a_0_n, a_1_n, ..., a_k_n]]

现在我们有一个列表列表,每个内部列表代表某些f_i的{​​{1}}。但是我们不想停止使用该表示,因为实际计算列表的i元素是j。因此,让我们使用来自O(j)的{​​{1}}代替:

Vector

现在我们有一个Data.Vector列表,每个列表代表一个listmapsf = map fromList listft 。我们可以使用Vector

将这些函数转换为函数
f_i

注意:这对于验证输入列表的长度是否完全没有任何作用。它可能也不是生成函数列表的最有效方法,但它并不是一个糟糕的方法。

修改:根据用户3237465的建议,我已使!functions = map (!) listmapsf 代表取代了IntMap

答案 3 :(得分:1)

这是一个很好的问题,值得应用于一般类型a -> [b]的任意函数。

我实际上对一元sequence函数做了一个related question,关于做一个相反的unsequence函数。它被证明是不可能。这就是原因:

当函数返回列表时,它可以是任意长度。这意味着我们只能在调用函数时确定返回列表的长度。因此,我们无法在不调用函数的情况下列出固定长度。

一种更简单的理解方法是想象我们已经在IO monad中获得了值。类型为IO [Int]。这与a -> [Int]完全相当,因为这两个值只有在它们保持在monadic类型内时才能被操纵。这与sequence :: Monad m => [m a] -> m [a]不同,因为[a] monad可以被解构,即:它也是一个comonad。

简单地说,&#39;纯粹&#39; monad只能被构造,因此你不能采用列表的长度,这是我们要从函数monad或IO monad中构造一个列表的基础。我希望这可以帮助你!

答案 4 :(得分:0)

如果您不需要所有值,则在需要之前不要计算它们。您只需要定义索引访问权限,即let frc r c = f!!r!!c其中r是行,c是列。