如何修复:ghci中的字符“”的字符串/字符文字中的词法错误

时间:2019-01-04 19:12:42

标签: haskell

练习中给出的这种类型用于逻辑命题。我想做的就是为此特定类型的Show定义一个实例。

这是我的代码:

data Prop = Var String | Not Prop | And Prop Prop | Or Prop Prop

p1::Prop
p1 = Not (Or (And (Not( Var "A")) (Var "B")) (Var "C"))

instance (Show Prop) where
    Var s = show s
    Not s = "-" ++ show s
    And s d = show s ++ "/\ " ++ show d
    Or s d = show s ++ "\/" ++ show d

例如,在show定义之后,上面定义的p1应该显示为: “-((-A / \ B)/ C)”

我收到此错误:

T1516.hs:48:33: error:
lexical error in string/character literal at character '"'

2 个答案:

答案 0 :(得分:2)

"\\/"而不是"\/"。以\开头的符号称为转义序列,没有\/序列。 \\序列仅输出\,这正是您所需要的。

请注意,这并非特定于Haskell语言。

答案 1 :(得分:2)

表达式"/\ "的解析方式如下:

  • ":字符串文字从此处开始。
  • /:正斜杠字符
  • \escape sequence的开始。字符串文字中的反斜杠不是解释为实际的反斜杠字符,该字符应出现在您要定义的字符串中,而是解释为引入这种转义序列的控制字符。但是...
  • :一个空格。空格不能是转义序列的一部分,但是仍然可以通过一种方法来完成:如果您要转义长字符串文字中的换行符。例如(突出显示换行符)

    foo :: String↲
    foo = " bla bla \      ↲
          \ bum blum blam \↲
          \ gum gao wo"↲
    

    是合法的字符串文字。反斜杠将其扩展到下一行,即直到该行的前导反斜杠为止,并且在尾随的反斜杠和行尾之间没有空格也没关系。您的代码中的内容虽然不正确:

  • "在这一点上是非法的,因为您已经开始了只能是换行符的转义序列,但这不是换行符。

您想要的是文字反斜杠。您可以使用转义序列\\

在字符串文字中实现该目标
  show (And s d) = show s ++ "/\\ " ++ show d
  show (Or s d) = show s ++ "\\/" ++ show d

如果字符串文字中有很多反斜杠,则可以考虑使用raw string literals,它们没有任何转义。

一个更好的选择是只使用适当的Unicode符号:

  show (And s d) = show s ++ "∧" ++ show d
  show (Or s d) = show s ++ "∨" ++ show d

这些都不需要以任何方式转义。


顺便说一下,这个Show实例不能真正正常工作,即它没有适当的分组/优先级。例如,And (Or a b) (Or c d)将呈现为a∨b∧c∨d,这在逻辑上是不同的。要获得正确的括号,您需要定义showsPrec而不是简单的show

instance (Show Prop) where
  showsPrec p (Var s) = showsPrec p s
  showsPrec p (Not e) = showParen (p>=7)
       $ ("¬"++) . showsPrec 7 e
  showsPrec p (And s d) = showParen (p>=3)
       $ showsPrec 3 s ++ "∧" ++ showsPrec 3 d
  showsPrec p (Or s d) = showParen (p>=2)
       $ showsPrec 2 s ++ "∨" ++ showsPrec 2 d

还要注意,Show实例应该吐出有效的Haskell代码被认为是一种良好的礼节。对于运算符,很容易实现:

infixr 3 ∧
(∧) = And
infixr 2 ∨
(∨) = Or

但是Haskell不支持前缀¬之类的前缀运算符。实际上,您可以通过实现一个-实例来获得前缀Num,但是请不要,这会非常令人困惑。因此,您最好将Not子句更改为仅产生"Not"

  showsPrec p (Not e) = showParen (p>=10)
       $ ("Not "++) . showsPrec 10 e