【问题标题】:What is the haskell equivalent of an interface?接口的haskell等价物是什么?
【发布时间】:2017-08-04 17:25:41
【问题描述】:

我想实现能够保证导出一组类似功能的模块。

举个例子:假设我想翻译一个词。每个单词都从源语言(比如English)映射到目标语言(比如SpanishRussian)。

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

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

具体行为在其中实现。

我该怎么做?

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

-- 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

【问题讨论】:

    标签: haskell design-patterns interface


    【解决方案1】:

    那就是类型类。来自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 Word Haskell on typeclasses

    【讨论】:

    • 有点错别字,应该是instance Translation Spanish where而不是instance Spanish Translation where
    • @FrankSchmitt 正如我在对李的回答的评论中所写的那样:如果我像您一样认真阅读文献,那将是我的回答。谢谢你,我很感激!但是,我会接受 Lee 的回答,因为“类型类用于重载,而不是数据抽象。”
    【解决方案2】:

    您可以创建一个包含所需功能的类型,例如

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

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

    【讨论】:

    • 我很好奇,为什么要输入记录而不是类型类?
    • @MichalCharemza 因为当您使用类型类C 用作Java 接口时,您很快就会被C 不是类型这一事实绊倒,并开始定义一个存在类型C 喜欢 data T = forall t. C t => T t。这是众所周知的 Haskell anti-pattern。注意:我主要同意卢克·帕尔默的观点,因为这通常是矫枉过正的,并且不会获得任何好处。使用具有功能的基本记录。然而,在某些特定情况下,我确实认为“反模式”是合理的。
    • @MichalCharemza - 我认为这种方法更简单,因为您不需要为每个翻译实例创建新类型(即SpanishTranslationRussianTranslation)。另一个优点是您可以将记录放入集合中并一起操作它们,这对于类型类来说很尴尬。我也认为这更接近于 OO 语言中接口的使用,其中行为与接收者而不是类型耦合。
    • 我不知道这种反模式是否与我相关。如果我想获得不同翻译的列表,我可以创建一个明确列出它们的类型,对吗?如果类型类定义了一种行为并且我不应该使用它们,那么它们还有什么用处?
    • @inktrap - 您的列表类型是什么?使用此解决方案,它将是 [Model] - 如果您使用类型类,则需要使用存在类型将 SpanishTranslationRussianTranslation 等放入同一个列表中,这要复杂得多。类型类用于重载,而不是数据抽象。
    【解决方案3】:

    class,有时称为“类型类”。不过不要将这与您通常的 OO 类混淆,Haskell 类没有数据,并且通常没有实现(通用默认值除外)。

    【讨论】:

    • 不是我的反对意见,但是“[类]通常没有实现(通用默认值除外)”是什么意思?您的意思是许多实现是自动派生而不是手工编写的吗?
    • 我的意思是类只定义函数的类型,它们不定义函数本身。这与 C++ 类不同,C++ 类通常但并不总是同时具有类型和实现
    猜你喜欢
    • 2011-05-25
    • 1970-01-01
    • 2018-11-30
    • 2012-01-01
    • 2022-11-03
    • 1970-01-01
    • 2014-05-08
    • 2014-06-12
    • 1970-01-01
    相关资源
    最近更新 更多