Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
递归Haskell函数,用于确定元素在列表中的位置_Haskell_Recursion - Fatal编程技术网

递归Haskell函数,用于确定元素在列表中的位置

递归Haskell函数,用于确定元素在列表中的位置,haskell,recursion,Haskell,Recursion,我有一段代码,它将返回字符数组中字符的索引,但是如果数组中没有值,我希望我的函数返回类似-1的值。如果元素不在数组中,函数将返回数组的大小。关于如何更改代码以应用此功能,您有什么想法吗 我尽量不使用任何花哨的函数来实现这一点。我只想要没有内置函数的简单代码 isPartOf :: [(Char)] -> (Char) -> Int isPartOf [] a = 0 isPartOf (a:b) c | a == c = 0 | otherwise = 1 + isP

我有一段代码,它将返回字符数组中字符的索引,但是如果数组中没有值,我希望我的函数返回类似-1的值。如果元素不在数组中,函数将返回数组的大小。关于如何更改代码以应用此功能,您有什么想法吗

我尽量不使用任何花哨的函数来实现这一点。我只想要没有内置函数的简单代码

isPartOf :: [(Char)] -> (Char) -> Int
isPartOf [] a = 0
isPartOf (a:b) c
    | a == c = 0
    | otherwise = 1 + isPartOf b c
例如:

*Main> isPartOf [('a'),('b'),('c')] ('z') 
3
但我想:

*Main> isPartOf [('a'),('b'),('c')] ('z') 
-1

让我们尝试定义这样一个函数,但是如果元素不是列表的一部分,我们不能返回-1,而是什么也不返回:

所以,它是这样工作的:

>> isPartOf [('a'),('b'),('c')] ('z')
Nothing
it :: Maybe Int

>> isPartOf [('a'),('b'),('c')] ('c')
Just 2
it :: Maybe Int
之后,我们可以使用内置函数将Nothing大小写转换为-1:

如果您对已经存在这样一个函数感到好奇,您可以使用Hoogle搜索[a]->a->Maybe Int函数:

第一个答案是:


希望这有帮助。

让我们尝试定义这样一个函数,但是如果元素不在列表中,我们不能返回-1,而不能返回任何内容:

所以,它是这样工作的:

>> isPartOf [('a'),('b'),('c')] ('z')
Nothing
it :: Maybe Int

>> isPartOf [('a'),('b'),('c')] ('c')
Just 2
it :: Maybe Int
之后,我们可以使用内置函数将Nothing大小写转换为-1:

如果您对已经存在这样一个函数感到好奇,您可以使用Hoogle搜索[a]->a->Maybe Int函数:

第一个答案是:


希望这有帮助。

如果您只需将当前元素idx传递给下一个递归,就可以轻松实现:

isPartOf :: [Char] -> Char -> Int
isPartOf lst c = isPartOf' lst c 0

isPartOf' :: [Char] -> Char -> Int -> Int
isPartOf' [] a _ = -1
isPartOf' (a:b) c idx
    | a == c = idx
    | otherwise = isPartOf' b c (idx + 1)

只要将当前元素idx传递给下一个递归,就可以轻松实现:

isPartOf :: [Char] -> Char -> Int
isPartOf lst c = isPartOf' lst c 0

isPartOf' :: [Char] -> Char -> Int -> Int
isPartOf' [] a _ = -1
isPartOf' (a:b) c idx
    | a == c = idx
    | otherwise = isPartOf' b c (idx + 1)

实现这一目标的最小变化是

isPartOf :: [Char] -> Char -> Int
isPartOf [] a = (-1)    -- was: 0
isPartOf (a:b) c
    | a == c = 0
    | otherwise = 1 +   -- was: isPartOf b c
          if  (isPartOf b c) < 0  then  (-2)  else  (isPartOf b c)
那-2看起来特别特别!使用guards的更紧凑、更惯用的版本也将允许我们解决这一问题:

isPartOf :: Eq a => [a] -> a -> Int
isPartOf [] a = (-1)
isPartOf (a:b) c
    | a == c    = 0
    | d < 0     = d 
    | otherwise = 1 + d
          where 
          d = isPartOf b c
这就是我们正在使用的。但当我们刚开始学习哈斯克尔时,这可能被视为一种幻想

当您编写了更多类似的函数,并且厌倦了一次又一次地手动重复相同的模式时,您将开始欣赏它并希望使用它。但只有到那时

还有一个问题是,我们的代码在从递归的基本情况返回的过程中计算其结果

但是它可以计算它,朝着它,所以当找到匹配的字符时,它可以立即返回它。如果找到了列表的末尾,则放弃到目前为止计算的结果,并返回-1。这就是我们所采取的方法

尽管创建一个附加函数会占用全局名称空间。通常通过在所谓的worker/wrapper转换中对其进行内部定义来实现这一点:

isPartOf :: Eq a => [a] -> a -> Int
isPartOf xs c = go xs 0
   where
   go [] i = (-1)
   go (a:b) i
    | a == c    = i
    | otherwise = -- go b (1 + i)
                  go b $! (1 + i)
另外一个好处是,我们不需要传递未更改的值c—从内部工作函数go的角度来看,它在外部范围内可用,由我们的函数isPartOf包装并仅可访问

美元!是一个特殊的调用运算符,它确保立即计算其参数值,而不是延迟。这消除了不必要的惰性,并进一步提高了代码效率

但从设计整体清洁度的角度来看,最好返回包装在a中的索引i,也就是说,仅i或无,而不是使用一个毕竟不那么特殊的特殊值——它仍然是一个Int

让类型反映我们的意图是很好的,也许Int可以清楚而清晰地表达它,所以我们不必记住哪些值是特殊的,哪些是规则的,这样这些知识就不是程序文本的外部知识,而是程序文本的固有知识

这是一个小而简单的更改,结合了前两个变体的最佳部分:

isPartOf :: Eq a => [a] -> a -> Maybe Int
isPartOf .....
  .......
  .......  Nothing .....
  .......
  .......  Just i  .....
  .......

所有代码都没有经过测试。如果有错误,我们会邀请您查找并更正错误,并通过测试进行验证。

实现这一点的最小更改是

isPartOf :: [Char] -> Char -> Int
isPartOf [] a = (-1)    -- was: 0
isPartOf (a:b) c
    | a == c = 0
    | otherwise = 1 +   -- was: isPartOf b c
          if  (isPartOf b c) < 0  then  (-2)  else  (isPartOf b c)
那-2看起来特别特别!使用guards的更紧凑、更惯用的版本也将允许我们解决这一问题:

isPartOf :: Eq a => [a] -> a -> Int
isPartOf [] a = (-1)
isPartOf (a:b) c
    | a == c    = 0
    | d < 0     = d 
    | otherwise = 1 + d
          where 
          d = isPartOf b c
这就是我们正在使用的。但当我们刚开始学习哈斯克尔时,这可能被视为一种幻想

当您编写了更多类似的函数,并且厌倦了一次又一次地手动重复相同的模式时,您将开始欣赏它并希望使用它。但只有到那时

还有一个问题是,我们的代码在从递归的基本情况返回的过程中计算其结果

但是它可以计算它,朝着它,所以当找到匹配的字符时,它可以立即返回它。如果找到了列表的末尾,则放弃到目前为止计算的结果,并返回-1。这就是我们所采取的方法

尽管创建一个附加函数会占用全局名称空间。通常通过在所谓的worker/wrapper转换中对其进行内部定义来实现这一点:

isPartOf :: Eq a => [a] -> a -> Int
isPartOf xs c = go xs 0
   where
   go [] i = (-1)
   go (a:b) i
    | a == c    = i
    | otherwise = -- go b (1 + i)
                  go b $! (1 + i)
另一个好处是,我们不需要传递不变的值c——从内部工作者的角度来看,它在外部范围内可用 Action go,由我们的功能isPartOf包装并仅可访问

美元!是一个特殊的调用运算符,它确保立即计算其参数值,而不是延迟。这消除了不必要的惰性,并进一步提高了代码效率

但从设计整体清洁度的角度来看,最好返回包装在a中的索引i,也就是说,仅i或无,而不是使用一个毕竟不那么特殊的特殊值——它仍然是一个Int

让类型反映我们的意图是很好的,也许Int可以清楚而清晰地表达它,所以我们不必记住哪些值是特殊的,哪些是规则的,这样这些知识就不是程序文本的外部知识,而是程序文本的固有知识

这是一个小而简单的更改,结合了前两个变体的最佳部分:

isPartOf :: Eq a => [a] -> a -> Maybe Int
isPartOf .....
  .......
  .......  Nothing .....
  .......
  .......  Just i  .....
  .......

所有代码都没有经过测试。如果有错误,我们会邀请您查找并更正错误,并通过测试进行验证。

您将函数用作累加器。这是很酷的,除了添加负一。累加器不能从累加切换到提供负1。您需要从函数累加器中获得两种不同的内容。您可以使用计数器进行一件事,如果由于未找到匹配项而导致计数变得不必要,则会发出负1,并且不会丢失任何内容。计数将是另一个参数。啊。你可以用Maybe,但这会让事情复杂化。上面的两个函数更简单。这里有两个函数。第一个是你的,但累加器不是加法的,而是串联的

cIn (x:xs) c | x == c    =  [1]
             | null xs   = [-1]
             | otherwise = 1:cIn xs c


Cin ['a','b','c'] 'c'
[1,1,1]

cIn ['a','b','c'] 'x'
[1,1,-1]

第二个函数是

f ls = if last ls == 1 then sum ls else -1 
会的

f $ Cin ['a','b','c'] 'c'
三,

-一,


您可以通过将[1]更改为[0]

将函数用作累加器来将索引基数归零。这是很酷的,除了添加负一。累加器不能从累加切换到提供负1。您需要从函数累加器中获得两种不同的内容。您可以使用计数器进行一件事,如果由于未找到匹配项而导致计数变得不必要,则会发出负1,并且不会丢失任何内容。计数将是另一个参数。啊。你可以用Maybe,但这会让事情复杂化。上面的两个函数更简单。这里有两个函数。第一个是你的,但累加器不是加法的,而是串联的

cIn (x:xs) c | x == c    =  [1]
             | null xs   = [-1]
             | otherwise = 1:cIn xs c


Cin ['a','b','c'] 'c'
[1,1,1]

cIn ['a','b','c'] 'x'
[1,1,-1]

第二个函数是

f ls = if last ls == 1 then sum ls else -1 
会的

f $ Cin ['a','b','c'] 'c'
三,

-一,


您可以通过将[1]更改为[0]

==和+是内置函数。==和+是内置函数。这种方法比另一个答案好,但您应该解释原因。这种方法比另一个答案好,但您应该解释原因。