haskell - 有没有更好的方法来编写 indexof 函数?
问题描述
我在haskell中写了一个indexOf函数。有没有更好的写法?我的第二个问题是在我的函数中,tails 函数是否被懒惰地评估?
以下是我的 indexof 函数
import Data.List
indexof :: String -> String -> Int
indexof lat patt = helper (tails lat) 0
where helper [] _ = -1
helper (x:xs) a = if prefix x patt then a else helper xs (a + 1)
prefix :: String -> String -> Bool
prefix _ [] = True
prefix [] _ = False
prefix (x:xs) (y:ys) = if x == y then prefix xs ys else False
这按预期工作。
解决方案
使用 ern 作为第一个参数看起来更习惯patt
,通常失败不是用-1
或其他值解决,而是通过使用Nothing
并因此Maybe Int
用作返回类型。
我们可以foldr
在这里使用一个模式,这使它更优雅,并且Data.List
有isPrefixOf :: Eq a => [a] -> [a] -> Bool
:
import Data.List(isPrefixOf, tails)
indexof :: Eq a => [a] -> [a] -> Maybe Int
indexof patt = foldr helper Nothing . tails
where helper cur rec | isPrefixOf patt cur = Just 0
| otherwise = fmap (1+) rec
然而,实现Knuth-Morris-Pratt 算法[wiki]可能会更好,因为这将导致在O(m + n)中搜索,其中m是模式的长度,n是字符串的长度。当前的方法需要O(m×n)。
我的第二个问题是在我的函数中是
tails
懒惰地评估函数吗?
tails
确实是懒惰评价。然而,瓶颈可能并不tails :: [a] -> [[a]]
存在,因为在评估列表上以O(n)tails
运行,并且还需要O(n)内存,因为指针是共享的。因此,它并没有真正为每个项目构建一个新列表,它只是每次都指向前一个元素的尾部。tail
推荐阅读
- c# - 如何在 Visual Studio C# 中获取当前正在运行的应用程序进程?
- kubernetes - 为单个副本设置有状态是否是矫枉过正?
- pandas - 了解pandas.DataFrame.corrwith方法用于spearman等级相关性计算列和行
- android - 如何更改选定的 BottomNavigationView 图标大小
- javascript - 如何在 node.js 中设置动态环境变量
- java - 如何在 Android 中模拟(或)测试方法级变量?
- c# - c# 对象在 Visual Studio 的 Locals 中可见,但在代码中不可用
- javascript - 获取 REST API 的错误请求响应
- javascript - 删除其他类时添加javascript类后播放CSS动画不播放
- angular - Angular 应用程序编译成功后呈现一个空白页面