Haskell中与接口相当的是什么?

4

我希望实现保证导出类似一组函数的模块。

以一个例子说明:假设我想翻译一个单词。每个单词都从源语言(比如英语)映射到目标语言(比如西班牙语和俄语)。

我的主应用程序将导入西班牙语和俄语模型并选择默认模型为俄语。我想保证每个模型都具有:

  • 一个函数translateToken :: String -> String
  • 一个函数translatePhrase :: String -> String

其中特定行为被实现。

我该怎么做?

编辑,关于Lee的回答:如何创建使用守卫的函数的记录语法包含数据类型?

-- let's suppose I want to use a function with guards in a record.
-- how can and should i define that?

data Model  = Model { translateToken :: String -> String}

-- idea 1) should I define the functions separately, like this?
-- how do I do this in a way that does not clutter the module?
f l
  | l == "foo" = "bar"

main :: IO ()
main = print $ translateToken x "foo"
  where
    x = Model {translateToken=f}
    -- idea 2) define the function when creating the record,
    -- despite the syntax error, this seems messy:
    -- x = Model {name=(f l | l == "foo" = "bar")}

-- idea 3) update the record later
3个回答

16
您可以创建一个包含您想要的函数的类型,例如:
data Model = Model { translateToken :: String -> String,
                     translatePhrase :: String -> String }

然后为西班牙语和俄语创建值。


1
我很好奇,为什么要使用记录类型而不是类型类? - Michal Charemza
7
@MichalCharemza 因为当你使用类型类 C 作为一个 Java 接口时,你很快会被 C 不是一种类型这个事实绊倒,并开始定义一个围绕 C 的存在类型,例如 data T = forall t. C t => T t。而这是一个众所周知的 Haskell 反模式。注意:我大多数情况下同意 Luke Palmer 的观点,即这种方式常常过度复杂,与使用带有函数的基本记录相比没有任何收益。但在某些特定情况下,我认为这种“反模式”是合理的。 - chi
2
@MichalCharemza - 我认为这种方法更简单,因为您不需要为每个翻译实例创建新类型(即SpanishTranslationRussianTranslation)。另一个优点是您可以将记录放入集合中并一起操作,而使用类型类会很麻烦。我还认为这更接近面向对象语言中接口的使用,其中行为与接收器耦合,而不是类型。 - Lee
我不知道这个反面模式是否适用于我。如果我想要获取各种翻译的列表,我可以创建一个列出它们的类型,是吗?如果类型类定义了一种行为,而我不应该使用它们,那么它们还有什么其他好处呢? - inktrap
@inktrap - 你的列表类型是什么?使用这种解决方案,它将是[Model]- 如果您使用类型类,则需要使用存在类型将SpanishTranslationRussianTranslation等放入同一列表中,这更加复杂。类型类用于重载,而不是数据抽象。 - Lee
显示剩余2条评论

3

这与类型类有关。来自Learn You a Haskell的描述:

“类型类更像是接口。”

您可以定义自己的类型类(未经测试):

  class Translation a where
    translateToken :: a -> String -> String
    translatePhrase :: a -> String -> String

并将其实现为

  instance Translation Spanish where
     translateToken = spanishTranslateToken
     translatePhrase = spanishTranslatePhrase

另请参见 《Real World Haskell》关于类型类的章节


有一个小错别字,应该是 instance Translation Spanish where 而不是 instance Spanish Translation where - jakubdaniel
@FrankSchmitt,就我在Lee的回答评论中写的内容而言:如果我像你一样仔细阅读文献,那将是我的回答。谢谢,我很感谢!不过,我将接受Lee的回答,因为“类型类是用于重载,而不是数据抽象的”。 - inktrap

-3
一个“类”(有时称为“类型类”)。不要将其与您通常使用的面向对象类混淆,Haskell 类没有数据,并且通常没有实现(除了通用默认值的例外)。

1
不是我点的踩,但你说的“[类]通常没有实现(除了通用默认值)”是什么意思?你是指许多实现是自动派生的,而不是手写的吗? - erisco
我的意思是,类仅定义函数的类型,而不定义函数本身。这与C++类不同,后者通常但并非总是具有类型和实现。 - Clinton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接