recursion - SML:LookSay 递归
问题描述
我正在自学函数式编程,没有老师可以指导我。谢谢你帮助我!
(*lookSay:int list=>int*int list
ENSURE: true
REQUIRE: computes the look-and-say sequence, for example list of l=[2,2,2] which would be read as "three twos" =>[(2,1),(1,2)] *)
这是我的代码:
fun lookSay(x:int list)=
case x of
[]=>[]
| l::ls =>
let fun helper(l,l'::ls',acc)=
if l=l'
then helper(l,ls',acc+1)
else (acc,l)::lookSay(ls)
in
helper(l,ls,1)
end
我不明白为什么它不起作用。其他人提供的解决方案是使用辅助函数 runWith(x,L) 返回 (repeated, tail) :但我不知道如何得出这个解决方案..
fun runWith (_:int, [] : int list) : int list * int list = ([], [])
| runWith (x, y::L) =
if x = y then
let
val (repeats, tail) = runWith(x, L)
in
(x::repeats, tail)
end
else
([], y::L)
解决方案
我将首先像这样格式化您的解决方案:
fun lookSay [] = []
| lookSay (x::xs) =
let
fun helper(y, z::zs, count) =
if y = z
then helper(y, zs, count + 1)
else (count, y) :: lookSay zs
in
helper(x, xs, 1)
end
我使用x
,y
而z
不是l
andl'
因为我发现它l
很难阅读:我无法轻易看出它是小写 L、大写 i 还是 1。因为我们实际上也在使用常量 1,这增加了混乱。
我还做了一些变量重命名:在 case-of 的范围内有一对l
and ,在辅助函数内部有另一对同名的and来隐藏外部变量。虽然这是可行的,但将不同的事物命名为相同的名称非常令人困惑。ls
l
ls
同样,我重命名acc
为count
以澄清它累积的内容。
正如 molbdnilo 暗示的那样,您的问题在于缺少模式匹配。ML 编译器应该警告您:
! Toplevel input:
! ..........helper(y, z::zs, count) =
! if y = z
! then helper(y, zs, count + 1)
! else (count, y) :: lookSay zs
! Warning: pattern matching is not exhaustive
哪些提示也helper
应该有一个[]
模式。
至于这个解决方案的策略:内部helper
函数做了两件事,需要一个内部辅助函数。首先,它有一个关于“当前”项目的额外参数,我称之为y
,其次,它有一个累积参数,我称之为count
。特殊的是,helper
调用lookSay
而不是自身。
但其中只有第二个是真正必要的,因为您还可以使用列表参数的头部来保留“当前”项目:
fun lookSay xs =
let
fun go [] _ = []
| go (x::y::zs) count =
if x = y
then go (x::zs) (count + 1)
else (count + 1, x) :: go (y::zs) 0
in
go xs 0
end
此策略一次查看列表的前两个元素,x
和y
,如果它们相等,则丢弃一个但递增count
。如果x
和y
不相等,则这标志着x
s 序列的结束,因此(count + 1, x)
发出一个元素并且go
可以在 上递归调用自身y::zs
。
我保留了您的示例中也存在的错误。在我的版本中,molbdnilo 的提示可以改写为“想想go
函数如何处理只有一个元素的列表”。
我认为为了让这个函数更有用,你实际上想要发出一个简单的列表:
fun concatMap f xs =
List.concat (List.map f xs)
fun flatten pairs =
concatMap (fn (n, x) => [n, x]) pairs
fun lookSay xs =
let
fun go [] _ = []
| go (x::y::zs) i =
if x = y
then go (x::zs) (i+1)
else (i+1,x) :: go (y::zs) 0
in flatten (go xs 0) end
假设错误得到修复,这应该给你:
- lookSay [1, 1, 1, 2, 2, 3];
> val it = [3, 1, 2, 2, 1, 3] : int list
推荐阅读
- python - 最小和最大功能来计算最小信用卡余额
- android - “命令失败:./gradlew installDebug”问题(react-native run-android)
- javascript - React Pagination:如何在点击时加载第二页数据
- html - 如果可能,我如何使用 selenium 来识别嵌套框架中的元素?
- wix3.10 - WiX 工具集灾难性故障运行 light.exe
- ios - 从另一个类访问@IBOutlet
- mysql - MySQL table.column 不更新
- c++ - 为什么下面的类不对数组 arr 进行浅拷贝?
- php - 在我提交时跨越输入字段并删除 html 文本
- react-native - React Native WebView onMessage IOS问题