【问题标题】:How to write a function returns either Integer or Bool based on a user defined data type?如何编写函数根据用户定义的数据类型返回 Integer 或 Bool?
【发布时间】:2015-11-29 14:29:57
【问题描述】:

我得到了如下的数据类型

data Value = IntVal Integer |
             BoolVal Bool
             deriving Show

我正在尝试编写一个函数getVal,它接受一个值并返回内部的实际值。我试图通过模式匹配来实现

getVal (IntVal val) = val
getVal (Bool bool) = bool

但是 Haskell 抱怨返回类型 无法将预期类型“整数”与实际类型“布尔”匹配

所以我给它一个签名返回一个类型变量

getVar :: Value -> a

但这也行不通

【问题讨论】:

  • 您希望如何使用该功能getVar
  • @Bergi 这个函数的实际逻辑比这更复杂,我只是想在继续之前至少获得输入和输出格式
  • @Bergi 如果考虑到类型推断,它确实是有意义的。请参阅我的答案中的示例
  • 不,我不是说函数本身的逻辑,这无关紧要。但是你觉得你会怎么打电话给getVar
  • @behzad.nouri:是的,但是您已将结果类型更改为Maybe,这样在输入意外时它可能会失败。

标签: haskell functional-programming polymorphism


【解决方案1】:

是的,这可以借助类型类或 GADT 来处理,或者您甚至可以利用 Data.Typeable 来使用 cast。但是,当您非常了解 Haskell 并且知道自己在做什么时,所有这些都是有用的。

在您的情况下,您应该真正尝试了解 Haskell 的一般工作原理。 Haskell 是关于强加明智的不变量,使编写“坏”程序变得不可能(嗯,我就是这么说的)。这是通过类型系统完成的,如果没有附加这些不变量,您将无法真正做任何事情。

所以现在,你不能对a 类型的东西做太多事情,因为你对它了解不多。如果您想从可以是 IntBool 的函数返回值(这实际上是可能的,请参见存在量化),您将能够对该值执行可以在 Int 上执行的操作 Bool。例如,您可以获得该值的文本表示。

您可能想要的不止这些。在这种情况下,您可能不应该尝试同时返回Int Bool,而无法了解结果究竟是什么。

因此,您可以执行以下操作:

getVar :: Value -> Either Int Bool

或者你可以直接派送:

case Value of
  IntVal  x -> doWhatYouWantToDoWithInteger x
  BoolVal x -> doWhatYouWantToDoWithBoolean x

这是 Haskell 的自然流程。在程序的每个分支中,您现在都知道自己在处理什么。

希望对你有帮助。

【讨论】:

    【解决方案2】:

    一种方法是使用类型类,使函数返回值具有多态性

    \> :t getVal
    getVal :: GetValue a => Value -> Maybe a
    

    通过一个简单的代码如下:

    data Value = IntVal Integer
               | BoolVal Bool
                 deriving Show
    
    class GetValue a where
        getVal :: Value -> Maybe a
    
    instance GetValue Integer where
        getVal (IntVal i) = Just i
        getVal          _ = Nothing
    
    instance GetValue Bool where
        getVal (BoolVal b) = Just b
        getVal           _ = Nothing
    

    让类型推断决定正确的功能:

    \> import Data.Maybe (fromJust)
    \> (3 +) .fromJust . getVal $ IntVal 5  -- getVal :: Value -> Maybe Integer
    8
    \> not . fromJust . getVal $ BoolVal False  -- getVal :: Value -> Maybe Bool
    True
    

    【讨论】:

      【解决方案3】:

      这是GADTs 的工作:

      {-# LANGUAGE GADTs #-}
      
      data Value a where
          IntVal  :: Integer -> Value Integer
          BoolVal :: Bool    -> Value Bool
      
      getVal :: Value a -> a
      getVal (IntVal  i) = i
      getVal (BoolVal b) = b
      

      【讨论】:

        【解决方案4】:

        user3237465 和 behzad.nouri 已为您的具体问题提供了答案。但是,我想知道您是否正在考虑与 OO 和动态类型语言进行类比。如果您将“值”作为函数的参数,那么您应该使用模式匹配来使用它所持有的值做正确的事情。因此,假设您正在编写一个函数“showValue”以将值作为字符串返回。我猜你正在尝试做类似的事情:

        showValue :: Value -> String
        showValue v = let v1 = getValue v in <something>
        

        但这在 Haskell 中行不通,因为类型系统坚持要知道“v1”是什么类型。相反,你可以这样写:

        showValue (IntVal i) = "The Value is an integer " ++ show i
        showValue (BoolVal b) = "The Value is a boolean " ++ show b
        

        【讨论】:

          猜你喜欢
          • 2015-09-07
          • 1970-01-01
          • 1970-01-01
          • 2015-10-23
          • 2022-08-19
          • 2011-06-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多