【问题标题】:Pattern matching data types in Haskell. Short cuts?Haskell 中的模式匹配数据类型。捷径?
【发布时间】:2009-11-12 02:54:06
【问题描述】:

在下面的 Haskell 代码中,如何写得更简洁?是否有必要列出所有四个条件,或者可以用更紧凑的模式来概括这些条件?例如,有没有一种方法可以利用 Haskell 已经知道如何添加 float 和 int,而无需手动指定 fromIntegral

data Signal = SignalInt Int | SignalFloat Float | Empty deriving (Show)

sigAdd :: Signal -> Signal -> Signal
sigAdd (SignalInt a) (SignalInt b) = SignalInt (a + b)
sigAdd (SignalInt a) (SignalFloat b) = SignalFloat ((fromIntegral a) + b)
sigAdd (SignalFloat a) (SignalInt b) = SignalFloat (a + (fromIntegral b))
sigAdd (SignalFloat a) (SignalFloat b) = SignalFloat (a + b)

main :: IO ()
main = do
  putStrLn (show (sigAdd (SignalFloat 2) (SignalInt 5)))

【问题讨论】:

    标签: haskell types pattern-matching


    【解决方案1】:

    Haskell 知道如何添加FloatInt;它对类型非常具体和明确:

    Prelude> (5 :: Int) + 3.5
    
    <interactive>:1:13:
        No instance for (Fractional Int)
          arising from the literal `3.5' at <interactive>:1:13-15
        Possible fix: add an instance declaration for (Fractional Int)
        In the second argument of `(+)', namely `3.5'
        In the expression: (5 :: Int) + 3.5
        In the definition of `it': it = (5 :: Int) + 3.5
    

    定义一个函数toFloatSig:

    toFloatSig (SignalInt a) = fromIntegral a
    toFloatSig (SignalFloat a) = a
    

    然后你可以写:

    sigAdd (SignalInt a) (SignalInt b) = SignalInt (a + b)
    sigAdd sa sb = SignalFloat (toFloatSig sa + toFloatSig sb)
    

    Signal 设为Num class 的一个实例也是合适的,这样您就可以使用+ 运算符直接添加它们。此外,您可以使类型更通用:

    data (Num a) => Signal a = Signal a | Empty deriving (Show)
    

    【讨论】:

    • > sigAdd sa sb = SignalFloat (toFloatSig a + toFloatSig b) 这应该是“...(toFloatSig sa + toFloatSig sb)”吗?谢谢。
    • 为什么“对数据构造函数没有约束的非常强的约定”在这里不成立?只是潜入haskell,阅读这条规则,所以我很好奇它是否适用于你的例子(如果不是 - 为什么)
    • @Al.G.将约束排除在外可能会更好。然后Signal 基本上会演变为Maybe,这可能很有用。但我也不是专家……
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多