首页 > 解决方案 > 在函数 Haskell 中创建一个变量

问题描述

我有两个字符串;一个主字符串,另一个是两个字符中的一个(例如“aa”)。

我想看看我的主字符串是否包含第二个字符串并在主字符串中打印它的索引。

我试图用自己压缩主字符串,这样我就可以检查一个接一个的字母的每个组合(例如“abab”=(a,b)(b,a)(a,b))。我用 [1..] 压缩这些元组以获得匹配字符串可能开始的正确索引((a,b)0)。然后我用 fst(fst h) 从元组中提取第一个字母,看看它是否与我的辅助字符串的第一个字母匹配。如果它没有找到任何匹配项,它应该在主字符串 (xs) 的其余部分上再次运行。我曾经where将变量声明hhead(locateZip x:xs)

locate (x:xs) (y:ys) = if fst(fst h) == y && snd(fst h) == ys then snd h else locate xs (y:ys)
                 where h = head(locateZip x:xs)
locateZip xs = zip(zip xs(tail xs)) [0..]

snd h用于打印元组的索引。

它应该返回如下内容:

locate "aabba" "aa" 
0

locate "bbaab" "aa"
2

我知道这可能看起来不寻常,但我还是新手,无法理解我得到的错误以及哪些有效,哪些无效。

我说错了h

Couldn't match expected type: ((Char, b2), b3) with actual type: [((b0, b0), b1)]

where语句是否正确用于此功能?

标签: haskell

解决方案


我在您的代码中发现了三个问题。两个是语法问题,一个是逻辑问题。我试图尽可能少地改变。

首先,在 where 语句中,必须使用 () 和 ":" 运算符:

where h = head(locateZip (x:xs))

在您的代码中,Haskell 为 locateZip 函数推断出不同的类型。

二、在下面的对比中

snd(fst h) == ys

ys 是一个列表,而不是一个字符。这是因为“:”运算符将列表拆分为列表的第一个元素和列表的尾部,就像在函数的开头发生的那样:

locate (x:xs) (y:ys)

现在,逻辑问题。使用 where,只要调用 locate 函数,您就会生成一个 zip 列表。但是,无论何时调用 locateZip 函数,都会重新生成索引。然后,在您最初的想法中,只要找到该对,定位函数就会输出 0。

还有另一个问题,因为您的定位函数在开始时没有保护来停止递归。好吧,经过一些更改,下面的代码似乎可以按您的预期工作:

locate [] _ = -1
locate phrase pair = locate_aux phrase pair (locateZip phrase)
locate_aux _ _ [] = -1
locate_aux (x:xs) (y1:y2:ys) h = 
    if (fst (fst (head h)) == y1) && (snd (fst (head h)) == y2) then 
        snd (head h) 
    else
        locate_aux xs (y1:y2:ys) (tail h)
locateZip xs = zip(zip xs(tail xs)) [0..]

推荐阅读