Haskell类型不匹配Int和[Int]

时间:2017-10-04 15:32:15

标签: haskell types int mismatch

我是Haskell的初学者。我正在尝试创建一个具有两个参数的函数:字符和字符串。 该函数应该遍历字符串并检查给定的字符是否在字符串中,然后返回表示字符串中字符位置的整数列表。

我的代码是:

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]]

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

2 个答案:

答案 0 :(得分: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表达式的结果的预期类型不匹配{1}}。

如果我正确理解你的问题(即,返回字符串中每个字符出现的整数位置列表,以便Int返回tegnPose 'a' "abracadabra",那么你应该 < / em>使用递归列表推导,但不能同时使用。

请注意非递归列表理解:

[0,3,5,7,10]

几乎做你想要的。缺少的只是测试条件以查看tegnPose c xs = [a | a <- [0..length xs - 1] 位置的字符是否为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

答案 1 :(得分: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. 的初始值
  4. 包含a
  5. 类型值的可遍历数据类型

    返回单个值b的值。

    在这种特殊情况下,我们的a类型值为Char类型,这使得t a成为String类型(由于类型签名)并且类型为b value是整数列表[Int]

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