我对Haskell完全不熟悉。我需要在一个字符串的给定索引处插入一个给定的字符串,该字符串可能已经是非空的。
这是我到目前为止所拥有的。但是,在看似没有错误运行之后,当我问t
的值是什么时,ghci只是无限期地挂起。
Haskell中:
create = ("",0,0,"","")
addText (m,l,p,_,k) i =
let a = take p m
m = drop p m
full = a++i++m
in (full, length full, p + length i, "", k)
m
是要添加的文字,l
是m
的长度,p
是开始添加新字符串的索引
输出:
*Main> t = create
*Main> t
("",0,0,"","")
*Main> t = addText t "test"
*Main> t
(hangs)
答案 0 :(得分:4)
let m = drop p m
是循环定义。它并不意味着“将m
设置为小于m
之前”,因为记住,在Haskell中修改变量是不可能的。相反,您忽略现有的m
,并定义一个名为m
的新变量,该变量根据其自身定义:永远无法完成的评估。这似乎是一个愚蠢的功能,但在其他情况下,根据自身定义值实际上非常有用,这就是语言允许的原因。
然后再次使用
犯同样的错误t = addText t "test"
根据自身定义t
。
您可以使用唯一命名的变量修复这两个错误,例如
r = addText t "test"
此时您将遇到令人兴奋的新错误:由于类型默认规则,create
的推断类型签名与addText
的推断类型签名不匹配。如果您指定显式类型签名,或者内联create
的定义,您将最终获得所需内容:
*Main> addText ("",0,0,"","") "test"
("test",4,4,"","")
答案 1 :(得分:2)
像许多刚接触Haskell的人一样,您可以用命令式样式编写函数,其中更新变量。
然而,Haskell中的变量无法更新:您没有(重新)为变量赋值,您声明了一个变量。如果你写i = i + 1
,你不取i
的旧值,并向其添加1
,你在这里声明i
自己的术语,i = i + 1
,意味着我们编写了一个无限深层的递归表达式i = ( ( (...) + 1) + 1) + 1
。
在您的功能中,您似乎更新了m
:
addText (m, l, p, _, k) i =
let a = take p m
m = drop p m
full = a++i++m
in (full, length full, p + length i, "", k)
所以你已经根据自己编写了m
,虽然由于懒惰这不会本身循环,如果m
的值是必要的,我们将陷入无限递归。
通过使用新变量,我们可以解决问题:
addText (m, l, p, _, k) i =
let a = take p m
z = drop p m
full = a++i++z
in (full, length full, p + length i, "", k)
如果你写的话会出现同样的现象:
Prelude> t = addText t "test"
你再次根据自己定义t
。因此,您最好使用另一个变量或常量:
Prelude> t = addText ("",0,0,"","") "test"