简体   繁体   English

Haskell中的OOP样式继承

[英]OOP style inheritance in Haskell

In C# I can declare the following 在C#中,我可以声明以下内容

class A {
    int Field;
}

class B : A {
    int Field2;
}

static int f(A a) { return a.Field; }
static int f(B b) { return a.Field + b.Field2; }

static void Main(string[] args) {
    A a = new A() { Field = 1 };
    A b = new B() { Field = 1, Field = 2};

    Console.WriteLine(f(a) + f(b));
}

In Haskell I would type out the above as 在Haskell中,我会输入上面的内容

data A = A { field :: Int } | B { field :: Int, field2 :: Int }

f :: A -> Int
f (A a) = a
f (B a b) = a + b

main :: IO()
main = do putStrLn $ show (f(a) + f(b))
    where a = A 1
          b = B 1 2

What I don't like about the Haskell counterpart is that I have to repeat field twice in the data definition of A (this becomes more tiresome as the number of fields increases that are present in A that need to be in B ). 我不喜欢的哈斯克尔对应的是,我要重复field中的数据定义两次A (这将成为为是在目前的场数量的增加更烦人的A需要在B )。 Is there a more concise way in Haskell to write B as a subclass of A (that is somewhat similar to the C# way)? 在Haskell中是否有更简洁的方法将B写为A的子类(有点类似于C#方式)?

If A has a lot of fields, one design that might make sense is to have two different datatypes for A and B, where a B contains an A, and then use a typeclass to define f. 如果A有很多字段,那么一个可能有意义的设计是为A和B提供两种不同的数据类型,其中B包含A,然后使用类型类来定义f。 Like so: 像这样:

data A = A {field1 :: Int, field2 :: Int, ..., field9999 :: Int}
data B = B {a :: A, field10000 :: Int}

class ABC a where
    f :: a -> Int

instance ABC A where
    f a = field1 a + field101 a

instance ABC B where
    f b = f (a b) + field10000 b

Your data definition is a lateral move, both the A and B constructors are instances of the type A, where what you're looking for is a type B that is-a type A but not just an instance of type A. 您的数据定义是横向移动,A和B构造函数都是类型A的实例,其中您要查找的是类型B,即类型A但不仅仅是类型A的实例。

Try: 尝试:

data Foo = Foo {field :: Type}
newtype Bar = Bar Foo

fromBar Bar x = x
toBar x = Bar x

This will allow you to declare all sorts of specialty functions on type Bar that will not apply to Foo, as well as operate on Bar using functions designed for type Foo. 这将允许您在Bar类型上声明不适用于Foo的各种特殊函数,以及使用为Foo类型设计的函数在Bar上操作。

If you want to extend the data parameters of Foo with additional information in Bar, you could use a data declaration and a has-a relationship. 如果要在Bar中使用附加信息扩展Foo的数据参数,可以使用数据声明和has-a关系。 This isn't as desirable as a newtype, as newtype is lazily evaluated where the data declaration is strict. 这不像newtype那样令人满意,因为在数据声明严格的情况下懒惰地评估newtype。 Still: 仍然:

data Foo = Foo {field :: Type}
data Bar = Bar {fooField :: Foo, moreField :: Type}

As sepp2k points out, what you really want to do to define the "nature" of a type is not by how it looks, but by how it works . 正如sepp2k指出的那样,你真正想要做的是定义一个类型的“本质”,不是它的外观,而是它的工作方式 We do this in Haskell by defining a type class, and having a type instance that class. 我们在Haskell中通过定义类型类并使用类的类型实例来完成此操作。

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM