Как иметь параметризуемые «методы» в структурах данных Elm - PullRequest
0 голосов
/ 01 октября 2019

Я застрял в рефакторинге большой структуры данных в Elm. Я знаю, как бы реализовать это на ОО-языках, но у меня нет опыта работы с ними. Я не могу точно выразить, в чем заключается моя проблема, потому что я могу сформулировать ее только в терминах ООП, которые не применяются. Итак, я приведу пример, который является упрощенной версией модуля, который я реорганизую.

Предположим, у меня есть этот тип:

type alias Book = { title : String, text : String }

, и у меня есть две книги:

englishBook = { title = "An English Book", text = "This book is an Eglish book." }
frenchBook = { title = "Un livre Francais", text = "Ce livre est un livre Francais." }

Есть связанная index функция для вычисления того, какие слова входят в Book:

index = String.words >> Set.fromList

Вот уже моя первая проблема. Когда index принимает строку, пользователь модуля должен знать, как взять текст из книги. Вместо этого мои привычки говорят, что функция должна сделать это для нас. Так что index может вести себя как метод и принимать Book в качестве первого аргумента: index = .text >> String.words >> Set.fromList. Но это также кажется странным.

Это еще не конец, потому что генератор индекса должен быть параметризуемым. В зависимости от книги, она должна делать разные вещи. Таким образом, я мог бы добавить функцию индекса следующим образом:

englishBook = { title = "...", text = "...", index = englishIndex }
frenchBook = { title = "...", text = "...", index = frenchIndex }

теперь у каждой книги есть функция для построения своего индекса. Но все же вызывающий абонент должен предоставить запись, когда ему нужен индекс:

wordsInEnglishBook = englishBook.index englishBook.text

, что не является хорошим решением для меня, поскольку он обременяет вызывающего абонента внутренними компонентами модуля. А что если эта часть инкапсулирована конструктором?

book title text index = { title = title, text = text, index = \_ -> index text }

Теперь я прошел полный круг и реализовал метод. Так каково идиоматическое решение для этого вяза ?

1 Ответ

2 голосов
/ 01 октября 2019

Вы можете использовать пользовательский тип для представления языка, а затем сопоставить шаблон с языком для выполнения индексации.

type Language
    = English
    | French


type alias Book =
    { title : String
    , text : String
    , language : Language
    }


wordsInBook : Book -> Set String
wordsInBook { language, text } =
    case language of
        English ->
            doSomethingWithEnglish text

        French ->
            doSomethingWithFrench text

или

type Book
    = Book Language Data


type Language
    = English
    | French


type alias Data =
    { title : String
    , text : String
    }


wordsInBook : Book -> Set String
wordsInBook (Book language data) =
    case language of
        English ->
            doSomethingWithEnglish data

        French ->
            doSomethingWithFrench data

...