【问题标题】:Haskell - How to concatenate a String to a list of StringsHaskell - 如何将字符串连接到字符串列表
【发布时间】:2015-01-21 09:39:34
【问题描述】:

我有一个字符串列表,我试图在以下代码中的列表末尾添加一个字符串,但出现类型匹配错误:

eliminateImpl :: [String] -> String -> [String]
eliminateImpl [] _ = []
eliminateImpl (p:ps) r = if (contains (p:ps) "Impl")
                         then if (p == "Impl" )
                              then "Not " ++r++" Or "++ps -- TRYING TO CONCATENATE HERE
                              else let r = r++p
                                   in eliminateImpl ps r
                          else (p:ps)

contains :: [String] -> String -> Bool
contains [_] [] = True
contains [] _ = False
contains (p:ps) c = if p == c
                    then True
                    else contains ps c

代码实际上做的是函数 eleminateImpl 采用一阶逻辑表达式,例如:“eliminateImpl [”Q(y)","Impl","P(x)"] []" 它应该删除蕴涵并修改表达式,使输出为:"eliminateImpl ["Not", "Q(y)"," Or ","P(x)"]

我尝试了 r++p 和 r:p 但两者都不起作用。这是错误:

无法将“Char”类型与“[Char]”匹配

Expected type: [String]

  Actual type: [Char]

In the first argument of ‘(++)’, namely ‘"Not "’

In the expression: "Not " ++ r ++ " Or " ++ ps

In the expression:

  if (p == "Impl") then

      "Not " ++ r ++ " Or " ++ ps

  else

      let r = r ++ p in eliminateImpl ps r

还有其他方法吗?

【问题讨论】:

  • 之后的字符串列表应该是什么样子?
  • 你能解释一下你不想做什么吗?我似乎无法理解你写的内容。
  • @SebastianRedl 函数应该得到一个一阶逻辑表达式,例如:"eliminateImpl ["Q(y)","Impl","P(x)"] []" 和函数应该删除隐含并修改表达式,使输出为:"eliminateImpl ["Not", "Q(y)"," Or ","P(x)"]"
  • 您想在这一行中将 ++ 替换为 :
  • 应该替换所有出现的“impl”还是只替换一个?

标签: string list haskell ghci


【解决方案1】:

类型注释:

r :: String
p :: String
ps :: [String]
-- We need to produce a [String], not a String

(++) :: [a] -> [a] -> [a]
(++) :: String -> String -> String -- Because String = [Char]

(:) :: a -> [a] -> [a]

"Not " ++ r ++ " Or " :: String
("Not " ++ r ++ " Or ") : ps :: [String]

此过程应指导您正确实施。仔细检查类型。我喜欢使用letwhere 来写中间值的类型注解;这样,当表达式不具有我期望的类型时,我会得到一个非常具体的类型错误。

【讨论】:

  • 我修复了它,但现在我得到一个“错误 - C 堆栈溢出”。任何想法为什么?
  • 另外 r 不是字符串,它也是一个 [String]。但不知何故,这工作得很好。 Stackoverflow 错误除外。
【解决方案2】:

如果我理解正确,这似乎接近你想要的:

EliminateImpl :: [String] -> [String]
EliminateImpl [] = []
EliminateImpl [x] = [x]
EliminateImpl (pred:impl:rest) str
    | impl == "impl" = ("Not" : pred : "Or" : (EliminateImpl rest))
    | otherwise = (pred : (EliminateImpl (impl : rest)))

如果我有误解,请评论,我会改变我的答案。

只替换一个含义:

EliminateImpl :: [String] -> [String]
EliminateImpl [] = []
EliminateImpl [x] = [x]
EliminateImpl (pred:impl:rest) str
    | impl == "impl" = ("Not" : pred : "Or" : rest)
    | otherwise = (pred : (EliminateImpl (impl : rest)))

这些函数应该遍历字符串列表,直到找到第一个"impl""impl" 之前的任何内容都不会更改。如果你想改变它,修改应该是微不足道的。

【讨论】:

  • 是的,逻辑是正确的。我修复了它只有轻微的语法问题,现在它可以完美运行。我很困惑,为什么在我自己的代码中修复了变量的附加后,我遇到了 stackOverflow 问题,但这个问题没有。
  • 在特殊情况之后用单个EliminateImpl xs = xs 情况替换两个终止情况不是更容易吗?
  • @SebastianRedl - 可能我只是不按这个顺序思考,可能是因为递归在命令式语言中的工作方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-07
  • 2017-01-17
  • 1970-01-01
  • 2014-04-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多