在函数式编程和Haskell中,函数内部有大量代码。
带有if语句(或大小写):
这是某些功能代码的一部分:
case x of
Apple i -> ...
Orange i -> ...
Tomato i -> ....
这很好,但是我有一个问题。
如何解决这个问题。
如果在库中使用此代码,并且每个开发人员都可以添加自己的类型。
像肉,香蕉等等。
以Haskell方式应在此函数中描述所有类型。
但这是不可能的,因为我不知道开发人员将添加什么。
由于在haskell中我没有对象中的方法,所以无法将方法放在对象本身上。
如何解决此问题。
答案 0 :(得分:3)
我认为这一切都是OO程序员将通过基类和继承解决的事情:
class Food {
private: int i;
public: virtual void eat() = 0;
};
class Apple: public Food {public: void eat(){crunch(i);}};
class Orange: public Food {public: void eat(){squeek(i);}};
class Tomato: public Food {public: void eat(){splosh(i);}};
...
class Meat: public Food {public: void eat(){malm(i);}}; // added by other developer
...
现在,作为一般规则,您应该记住,此类OO类与Haskell类不同,并且可以更好地用变量类型表示-就像您在回答中所假定的那样。
data Food = Apple Int | Orange Int | Tomato Int
eat :: Food -> IO ()
eat (Apple i) = crunch i
eat (Orange i) = squeek i
eat (Tomato i) = splosh i
与继承层次结构相比,变体类型通常更易于使用和安全,这恰恰是因为知道可能会遇到哪些构造函数。
但是,与“开放世界”相反,可以添加不同类型的新对象 绝对是现实的要求,而 可以通过类< / p>
class Edible f where
eat :: f -> IO ()
data Apple = Apple Int
instance Edible Apple where eat (Apple i) = crunch i
data Orange = Orange Int
instance Edible Orange where eat (Orange i) = squeek i
data Tomato = Tomato Int
instance Edible Tomato where eat (Tomato i) = splosh i
...
data Meat = Meat Int --- added by other developer
instance Edible Meat where eat (Meat i) = malm i
...
与变体类型的主要区别在于,所有不同类型的Edible
实际上具有不同的类型,因此您不能在包含Apple
和{ {1}}个。好吧,您无法完成...
在OO中,它们也是不同的类型,但是您可以拥有基类引用,它们实际上指向派生对象。 Haskell不直接支持此功能,但是它有一个GHC扩展支持:这称为 existential类型,也可以编写为
Orange
或
{-# LANGUAGE GADTs #-}
data Food where
Food :: Edible f => f -> Food
请注意,这是somewhat frowned upon,只有在您确定这对您的应用程序是个好主意时,才这样做。
如果您实际上不需要类型区分,那么应该考虑是否真的需要任何其他标签 。为什么不做它
{-# LANGUAGE ExistentialQuantification, UnicodeSyntax #-}
data Food = ∀ f . Edible f => Food f
您仍然可以添加另一个字段来说明您正在处理的食物
data Food = Food {eat :: IO ()}
apple :: Int -> Food
apple i = Food $ crunch i
orange :: Int -> Food
orange i = Food $ squeek i
tomato :: Int -> Food
tomato i = Food $ splosh i
...
meat :: Int -> Food -- added by other developer
meat i = Food $ malm i