在面向对象的编程语言中,您经常有多个构造函数来设置类的对象,例如,MyInteger
对象可以从内置的int或字符串构造:
class MyInteger {
int _value;
MyInteger (int value) {
_value = value;
}
MyInteger (String value) {
_value = String.parseInt(value);
}
}
在Haskell中执行此操作的惯用方法是什么?据我所知,在Haskell中总和类型
data MyInteger = Integer Int | String String
可以是Integer
或String
,也不是上述oo示例中的单一类型。我无法为值构造函数String
定义一个逻辑,它将采用String
和"返回" MyInteger
。
我是否必须定义这样的单独函数:
myIntegerFromString :: String -> MyInteger
myintegerFromString inputString = ...<parsing logic on inputString>....
然后每当我想从字符串
创建MyInteger
时调用它
main = do
...
let aMyInteger = myIntegerFromString "4"
...
附录:
创建一个&#34;对象&#34;来自Int
和String
仅仅是一个最小的例子。我对使用类型X的变量的一般方法更感兴趣,这些变量可以从各种其他类型Y,Z,...创建,以及如何在Haskell中解决这个问题。正是因为我不想在以面向对象的方式思考时滥用Haskell,所以我要求在Haskell中对这种模型进行建模。这就是为什么解决Int
来自String
s的解析的解决方案太具体了。
答案 0 :(得分:2)
在您的示例中,MyInteger
始终包含int
,但有时通过首先将字符串解析为int来构造String
。这不等同于data MyInteger = Integer Int | String String
,而是等同于newtype MyInteger = MyInteger Int
,smart constructor用于从字符串构建:
newtype MyInteger = MyInteger Int
mkMyIntegerStr :: String -> MyInteger
mkMyIntegerStr = MyInteger . read
需要注意的是,并非所有字符串都具有作为int的有效解析,并且在类型系统中确认此失败模式会更加健壮:
mkMyIntegerStr :: String -> Maybe MyInteger
mkMyIntegerStr = fmap MyInteger . readMaybe
来自Text.Read
模块的readMaybe
。
总的来说,我认为最好是用新鲜的眼睛来接近Haskell,而不是试图将熟悉的OOP概念映射到它上面。试图将FP视为一种奇怪的OOP形式,导致许多学习者误入歧途。
答案 1 :(得分:1)
Haskell程序员使用'smart constructor'模式来执行此操作。需要说明的是,这不是设计选择,这是设计必需品。根本不可能完全按照你在Haskell中的OOP示例中所做的那样。
事实上,您可以在Data.Text
模块中看到此样式。以下是Text
类型的原始定义:
data Text = Text
{-# UNPACK #-} !A.Array
{-# UNPACK #-} !Int
{-# UNPACK #-} !Int
deriving (Typeable)
即使我是专家,我也不想触及它。但是,有一个很好的小智能构造函数:(虽然不可否认它不执行检查)
pack :: String -> Text
pack = unstream . S.map safe . S.streamList -- Scary internals handled cleanly.
但为什么我们没有内置这种面向对象的风格?因为构造函数的内部工作对您来说是隐藏的,所以当您编写new MyInteger("123")
时,您并不确切知道可能会发生什么。这直接违反了Haskell的基本原则之一参考透明度。
相反,Haskell程序员可能会将上述类翻译为:
newtype MyInteger = MyInteger Integer
parseMyInteger :: String -> MyInteger
parseMyInteger = -- (whatever implementation here)
总之,在编写Haskell时忘记面向对象的编程(除非你是being experimental)。 Haskell有一个完全不同的范例,所以使用它而不是OOP概念。