2017-10-04 150 views
1

我是一个初学者哈斯克尔。我试图创建一个有两个参数的函数:一个字符和一个字符串。 该函数应该检查字符串,并检查给定的字符是否在字符串中,然后返回表示字符串中字符位置的整数列表。Haskell的类型不匹配INT和[INT]

我的代码是:

tegnPose :: Char -> String -> [Int] 
tegnPose c [] = [] 
tegnPose c (x:xs) = [if not (xs !! a == c) 
then [a] ++ tegnPose c xs 
else tegnPose c xs |a <- [0.. length xs - 1]] 

这与列表理解递归函数。

的错误,我得到:

Uke4.hs:14:7: error: 
    * Couldn't match expected type `Int' with actual type `[Int]' 
    * In the expression: [a] ++ tegnPose c xs 
     In the expression: 
     if not (xs !! a == c) then [a] ++ tegnPose c xs else tegnPose c xs 
     In the expression: 
     [if not (xs !! a == c) then 
      [a] ++ tegnPose c xs 
     else 
      tegnPose c xs | 
      a <- [0 .. length xs - 1]] 
    | 
14 | then [a] ++ tegnPose c xs 
    |  ^^^^^^^^^^^^^^^^^^^^ 

Uke4.hs:15:7: error: 
    * Couldn't match expected type `Int' with actual type `[Int]' 
    * In the expression: tegnPose c xs 
     In the expression: 
     if not (xs !! a == c) then [a] ++ tegnPose c xs else tegnPose c xs 
     In the expression: 
     [if not (xs !! a == c) then 
      [a] ++ tegnPose c xs 
     else 
      tegnPose c xs | 
      a <- [0 .. length xs - 1]] 
    | 
15 | else tegnPose c xs |a <- [0.. length xs - 1]] 

我不明白的不匹配是如何发生的,因为递归函数应该只运行通过。

+1

默认情况下,列表理解返回一个列表。试图返回里面的另一个列表给你列表,这不是你想要的。我会重写,以避免理解。 –

回答

5

这也是为什么错配情况。首先,请注意,返回[a]类型的列表,列表理解必须生成a型的元素,所以你必须满足下列条件相匹配:

example :: [Int] 

-- .-- the final value is "[Int]" 
-- | 
example = [ 2+x*y | x <- [1..10], y <- [1..5], x < y] 
--   ^^^^^ 
--   | 
--   `- therefore, this must be "Int" 

在你的榜样,为tegnPose类型签名意味着列表理解必须返回一个[Int],但表达式生成列表元素,即:

if ... then [a] ++ tegnPose c xs else tegnPose c cx 

显然返回它应该到纯Int的方式。

第一错误消息,指示实际类型子表达式[a] ++ tegnPos c xs这是[Int]不匹配整个if .. then .. else表达应该具有类型Int的结果的预期的类型。

如果我正确理解你的问题(即,在一个字符串返回字符的每次出现的整数位置的列表,以便tegnPose 'a' "abracadabra"回报[0,3,5,7,10],那么你应该要么使用递归列表理解, 。但不能同时

注意,非递归列表解析:

tegnPose c xs = [a | a <- [0..length xs - 1] 

几乎你做什么佤NT。所有缺少的是测试条件以查看位置a上的字符是否为c。如果您不清楚在列表解析中使用“警卫”,请查看它。

另外,递归函数没有一个列表理解:

tegnPose c (x:xs) = if (x == c) then ??? : tegnPose c xs 
           else tegnPose c xs 
tegnPose _ [] = [] 

几乎你想要做什么,但它不是很明显要放什么地方的???返回一个数字,表示当前位置。如果你写一个递归版本,一个额外的参数:

tp n c (x:xs) = if (x == c) then n : tp (???) c xs 
          else tp (???) c xs 
tp _ _ [] = [] 

的想法,你可以定义:

tegnPose c xs = tp 0 c xs 

,那么你会更接近,只要你能想出什么新的价值n应该代替???

更多标准Haskell的解决方案可能会涉及像拉链的事情:

> zip [0..] "abracadabra" 
[(0,'a'),(1,'b'),(2,'r'),...] 

和过滤器:

> filter (\(i,c) -> c == 'a') $ zip [0..] "abracadabra" 
[(0,'a'),(3,'a'),...] 

和地图:

> map fst $ filter (\(i,c) -> c == 'a') $ zip [0..] "abracadabra" 
[0,3,5,7,10] 

或寻找在Data.List的,做了功能你想要什么:

> elemIndices 'a' "abracadabra" 
[0,3,5,7,10] 
+0

非常感谢您的彻底回应。我发现它很有帮助= ^) – TropicalOverflow

1

只是为了某种变化,一个简单的方法实现这个功能与一个foldr可能是;

import Data.Bool (bool) 
charIndices :: Char -> String -> [Int] 
charIndices c = foldr (\t r -> bool r (fst t : r) (snd t == c)) [] . zip [0..] 

*Main> charIndices 't' "tektronix test and measurement instruments" 
[0,3,10,13,29,34,40] 

说明:

foldr类型是Foldable t => (a -> b -> b) -> b -> t a -> b

它有三个参数;

  1. 接受两个参数
  2. 类型b
  3. 持有型a

一个返回b类型的单个值的值可横越的数据类型的初始值的功能。

在这种特殊情况下,我们a类型值为Char类型,这使得t a一个String型(由于签名类型),然后键入b值为整数[Int]的列表。

作为第一个参数提供的功能是(\t r -> bool r (fst t : r) (snd t == c))如果您检查Data.bool,这非常简单。 boola -> a -> Bool -> a类型的三元运算符,它有三个参数。为了他们是否定的结果,积极的结果和条件。 (像Haskell一样,负数在左边)。它检查当前字符是否等于我们的目标字符c,如果是,则返回fst t : r如果不是rr表示结果)。最后t是fed元组列表的当前元组。元组列表由zip [0..] s构成,其中s由于部分应用程序未在函数定义中显示。

+0

这对我来说并不简单。 –

+0

@DanielWagner我附上了解释我的答案。 – Redu

相关问题