【问题标题】:Creating a Coordinate class in Haskell在 Haskell 中创建一个坐标类
【发布时间】:2016-11-26 19:32:48
【问题描述】:

我正在尝试以成对的方式将两个多态元组添加在一起。 (一个元组中的第一个元素的类型应该与第二个中的第一个元素的类型相同,第二个元素的类型也一样) 这是我的代码:

module Main where

class Coordinate a where

    createCoordinate :: a

    getFirst :: (a,b) -> a

    getSecond :: (a,b) -> b

    addCoordinates :: (a,b) -> (a,b) -> (a,b)

instance Coordinate () where

    createCoordinate = ()

    getFirst (a,b) = a

    getSecond (a,b) = b

    addCoordinates a b = (getFirst a + getFirst b, getSecond a + getSecond b)

所以,问题在于我的 addCoordinates 函数。我想知道是否有人可以为我提供有关如何实现该功能的任何帮助。 谢谢! :)

【问题讨论】:

  • 是的,我对 Haskell 很陌生。我以前的编程经验是使用 Java。有什么具体的我可以为你澄清一下吗?
  • 为什么所有类的函数都在元组而不是坐标上工作?您的大多数方法都具有b 类型变量的目的是什么-例如为什么要使用第一个元素是坐标而第二个元素是任意元素的元组?单位值作为坐标有什么意义?
  • 我不认为你想要class 这里。您不想让任意类型表现为坐标。您需要一个包含一对值的数据类型。
  • 你不使用类型类来建模数据,所以你开始使用完全错误的任务来学习类。如果这是您的主要目标,那么放弃并寻找不同的锻炼方式会更好地为您服务。 Haskell 中的类与 OO 语言中的类不同,它们更类似于 OO 接口。您使用数据类型对数据进行建模。类用于对许多不同类型可能想要实现的抽象接口进行建模(每个都以自己独特的方式)。
  • 在您有足够的使用其他人定义的类的经验之前,您不应该开始定义自己的类。 Haskell 程序员通常会定义大量的数据类型,而我们往往对类更加克制。制作一个没有捕捉到真正抽象的“用于实践”可能没有那么有帮助。练习使用ShowReadOrdFunctorApplicativeMonadTraversableMonoidCategory 等并编写实例。然后尝试制定表示涉及一个或多个操作的特定概念的类。试着写一个Ring 类,比如说。

标签: haskell


【解决方案1】:

你可能想要一个数据类型,而不是一个类:

data Coordinate a b = Coordinate { getFirst :: a, getSecond :: b }
    deriving (Eq, Ord, Show)

你的函数会变成:

createCoordinate :: a -> b -> Coordinate a b
createCoordinate a b = Coordinate a b

addCoordinates :: (Num a, Num b) => Coordinate a b -> Coordinate a b -> Coordinate a b
addCoordinates (Coordinate a1 b1) (Coordinate a2 b2) = Coordinate (a1+a2) (b1+b2)

注意ab 可以是任何类型,但addCoordinates 仅在它们是Num 的实例时才有效,因为我们希望将+ 应用于它们。您不需要类型类来定义Coordinate

类型类允许您定义可以初始化为默认值的事物,例如:

class DefaultInitializable a where
    defaultInit :: a

然后我们可以让Int 成为这个类的一个实例:

instance DefaultInitializable Int where
    defaultInit = 0

而且我们可以让Coordinate 成为一个实例,只要它的参数也是实例:

instance (DefaultInitializable a, DefaultInitializable b) => DefaultInitializable (Coordinate a b) where
    defaultInit = Coordinate default default

【讨论】:

  • 我试图以此作为学习类的练习,我认为上述可能是一个很好的解决方案,但我不知道它是否真的有助于我学习多态类和实现这些类的实例。不过感谢您的帮助。
  • 您可以为可以默认初始化的事物创建一个类,并使用它来实现 createCoordinate(假设 a 和 b 是默认可初始化的)。
  • 我不太确定我理解你的意思是默认初始化,你能解释一下吗?
  • 把类想象成你想应用于任意名词的动词集合,把数据类型想象成名词。坐标是名词。 DefaultInitializable 有一个动词 default 可以返回一个名词
  • 为什么不将字段访问器与数据类型捆绑在一起呢? data Coordinate a b = Coordinate { getFirst :: a, getSecond :: b } deriving (Eq, Ord, Show)?
【解决方案2】:

我觉得这可能是我想要的解决方案

module Main where

class Coordinate c where

    createCoordinate :: x -> y -> c x y

    getFirst :: c x y -> x

    getSecond :: c x y -> y

    addCoordinates :: (Num x) => (Num y) => c x y -> c x y -> c x y

instance Coordinate (,) where

    createCoordinate a b = (a,b)

    getFirst (a,_) = a

    getSecond (_,b) = b

    addCoordinates a b = (getFirst a + getFirst b, getSecond a + getSecond b)

【讨论】:

  • 但问题是,这个类对你有什么好处,而不是简单地在纯单态(a,b) 元组上使用合适的函数?或者确实是像R2 这样的矢量类,甚至更好的VectorSpace,它确保元素以统一的方式处理。尽管如此,我认为这个想法可能对完全不同的应用程序有用。它启发了我to a new question
猜你喜欢
  • 2011-09-12
  • 1970-01-01
  • 2019-02-06
  • 1970-01-01
  • 2013-02-23
  • 1970-01-01
  • 1970-01-01
  • 2021-11-11
  • 1970-01-01
相关资源
最近更新 更多