定义辅助函数并不是“作弊”,而是很好。
一个更大的问题是你定义了一个错误类型的函数 - 的类型expand
对于练习来说,比最终得到的函数数量更重要(请注意,描述说明了类型“必须是什么”,但并不是不允许您定义辅助函数)。
您遇到问题是因为您试图立即“攻击”整个输入列表。
当你遇到“对列表中的每个元素执行 X 操作”的问题时,首先要做的就是思考“编写一个函数,用以下命令执行 X 操作”:one事情然后List.map
it".
如果我们有一个可以重复某些事情的函数k
有时,我们可以将其应用于每个列表元素。
我们可以写repeat: int * 'a -> 'a list
,但这既需要一个数字又需要一个东西,并且不方便map
任何地方。
如果我们可以动态“修复”数字并获得一个函数,那就太好了'a -> 'a list
.
如果您以方便的顺序给出参数,柯里化就可以让您做到这一点。
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
几乎是正确的 - 列表应该是“平坦的”。
幸运的是,列表结构 http://sml-family.org/Basis/list.html#SIG:LIST.list:TY:SPEC有一个功能可以帮助: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