你能在 Elm 中让一个函数接受不止一种类型吗?你能有一个重载的功能吗?

Can you make a function take more than one type in Elm? Can you have an overloaded function?

我正在尝试从 JS 移植一个库,我得到了一个可以接受字符串或字符串列表的函数。如果给定一个字符串,它将把它分成一个字符串列表,然后继续,就像它首先被传递一样。

我可以通过定义自己的类型来做到这一点,但这会使 API 难看并且需要自定义类型前缀您的数据。

这是我得到的:

type DocumentBody = Raw String | Words List String

tokenize: DocumentBody -> List String
tokenize s = 
    case s of
        Raw str_body -> String.split " " str_body |> (List.map String.toLower)
        Words list_body -> List.map String.toLower list_body

-- Tests

tests = 
    suite "Tokenizer"
    [ test "simple" <| assertEqual ["this", "is", "a", "simple", "string"]
                                   <| tokenize (Raw "this is a simple string")

    , test "downcasing tokens: string" <| assertEqual ["foo", "bar"]
                                                      <| tokenize (Raw "FOO BAR")

    , test "downcasing tokens: list of str" <| assertEqual ["foo", "bar"]
                                                           <| tokenize (Words ["Foo", "BAR"])
    ]

最后,我认为端口不应该支持这种行为,但是如何只对类型的枚举进行模式匹配而不需要前缀 RawWords 在我的例子中?

不,您不能像在其他语言中那样在 elm 中重载函数。每个函数都有一个签名。如果你想让一个函数接受一个可以是多种类型的参数,你使用联合类型的解决方案就可以了。

你说这让 API 变丑了。我不会说它丑陋。也许类型声明或 case 语句的语法没有吸引力,但我说,给它时间。它会在你身上成长。那里有很多力量和安全。您不会让代码做出任何假设,您被迫处理每个场景,这是使用像 elm 这样的语言工作的优势之一。

您的模式匹配代码是合适的。不能再缩短了。

同时,我可以理解重写 javascript 库和尝试通过原始端口 javascript 进行通信的痛苦。你正在用一种更严格的语言重写东西,你将无法复制 javascript 中接受任何东西的函数签名。但同样,这是榆树的优势,而不是弱点。借此机会收紧 API 并消除歧义。

当谈到您的具体示例时,我觉得除了您的解决方案之外还有一些可能的替代方案。我认为 tokenize 函数一开始就很有希望;这太模棱两可了。在用函数式语言编写代码时,我更喜欢保持小而可组合。对我来说,它实际上应该是两个独立的功能,每个功能都有一个特定的目的。