定义辅助函数不是“作弊”,这很好。
这是一个更大的问题,你定义了一个错误类型的函数 - expand 的类型比你最终得到的函数的数量更重要(请注意,描述说明了“必须是”类型,但是并不是说你不能定义辅助函数)。
您遇到问题是因为您试图一次“攻击”整个输入列表。
当您遇到“对列表的每个元素执行 X”问题时,首先要做的是考虑“编写一个函数,用 one 执行 X,然后 List.map 它”。
如果我们有一个可以重复k 次的函数,我们可以将它应用于每个列表元素。
我们可以写repeat: int * 'a -> 'a list,但这需要一个数字和一个东西,而且在任何地方map 都不方便。
如果我们可以动态“修复”数字并获得一个函数'a -> 'a list,那就太好了。
如果您以方便的顺序给出参数,Currying 可以让您完全做到这一点。
fun repeat 0 i = []
| repeat n i = i :: repeat (n - 1) i;
加载和测试:
val repeat = fn : int -> 'a -> 'a list
val it = () : unit
- repeat 3 4;
val it = [4,4,4] : int list
目前看起来不错。
我们现在可以编写repeat 4 并获得一个接受“某物”并重复四次的函数。
让我们使用它:
- fun expand xs n = List.map (repeat n) xs;
val expand = fn : 'a list -> int -> 'a list list
字体看起来不太好。让我们看看我们刚刚创建了什么。
- expand [1,2,3] 3;
val it = [[1,1,1],[2,2,2],[3,3,3]] : int list list
几乎正确 - 列表应该是“扁平的”。
幸运的是,List structure 有一个可以提供帮助的函数:concat: 'a list list -> 'a list,它获取列表列表并将它们附加在一起,因此我们可以将结果传递给它:
- fun expand xs n = List.concat (List.map (repeat n) xs);
val expand = fn : 'a list -> int -> 'a list
这样看起来更好。
- expand [1,2,3] 3;
val it = [1,1,1,2,2,2,3,3,3] : int list