Dict.map
- это функция, которая преобразует значения Dict
и возвращает еще одно Dict
с новыми значениями. Это не то, что вам нужно, но давайте все равно попробуем использовать его тип, потому что это полезный опыт обучения.
Dict.map
A Dict
s полный тип равен Dick k v
, что означает, что переменные типа соответствуют типу его ключей и значений соответственно. Dict.map
, согласно документации , имеет тип (k -> a -> b) -> Dict k a -> Dict k b
. В качестве первого аргумента он принимает функцию из двух аргументов k
и a
, которая возвращает b
. Второй аргумент map
- это Dict k a
, и он возвращает Dict k b
.
Мы можем видеть, что k
одинаков как для ввода, так и для возврата Dict
с, что означает, что его тип останется прежним, но переменная типа для значений отличается, a
на входе и b
в ответ Dict
. И функция аналогично принимает a
в качестве одного из своих входов вместе с k
и возвращает b
. Таким образом, для каждой из пар ключ-значение во входе Dict
функция отображения будет вызываться с ее ключом 'k' и значением 'a' и, как ожидается, вернет значение b
.
Для Dict Int Int
, как у вас есть, k
и v
равны Int
с. Если мы подставим их в тип Dict.map
, мы получим (Int -> Int -> b) -> Dict Int Int -> Dict Int b
. Мы пока не знаем, что такое b
, поскольку это будет определяться функцией, которую мы передаем, но мы можем по крайней мере увидеть, что функция ожидает два Int
аргумента`.
Между тем, функция, которую вы ей даете, toLiDict
, имеет тип Dict Int Int -> Html msg
, который принимает один аргумент, который не является Int
. Это то, что сообщение об ошибке неуклюже пытается передать. Мы могли бы переписать toLiDict
, чтобы соответствовать тому, что ожидает Dict.map
, как функцию Int -> Int -> Html msg
, но при этом Dict.map
вернул бы Dict Int (Html msg)
, что не то, что вам нужно. Итак, давайте отбросим это.
В общем случае функции map
традиционно преобразуют элементы коллекции без изменения типа коллекции.
Dict.foldl
Если вместо этого вы хотите полностью преобразовать элементы коллекции во что-то еще, и не существует чего-то более специфичного для использования, «складывание» обычно является правильным инструментом. Dict
обеспечивает foldl
и foldr
, что в основном делает то же самое, но в другом порядке, foldl
перебирает элементы «слева» и foldr
«справа». Если порядок не имеет значения, используйте foldl
, потому что он более эффективен.
Подпись типа Dict.foldl
является (k -> v -> b -> b) -> b -> Dict k v -> b
. То есть функция преобразования теперь принимает три аргумента: ключ k
, значение v
и b
, которые мы назовем аккумулятором, и возвращает b
. Сам по себе foldl
также принимает дополнительный аргумент, снова b
, который будет начальным значением b
, переданным функции преобразования. Третий аргумент - Dict
, а возвращаемое значение снова равно b
.
Для каждой пары ключ-значение на входе Dict
, foldl
будет, как и map
, вызывать функцию преобразования со своим ключом и значением. Но он также предоставляет b
, который изначально является значением b
, переданным самому foldl
, но для последующих итераций будет значение b
, возвращаемое из функции преобразования. Таким образом, «аккумулятор» накапливает возвращаемое значение.
Давайте перепишем ваш код для использования Dict.foldl
вместо:
toHtmlDict : Dict Int Int -> Html msg
toHtmlDict dict =
div [] (Dict.foldl toLiDict [] dict)
toLiDict : Int -> Int -> List (Html msg) -> List (Html msg)
toLiDict k v acc =
div [] [ text "What here?" ] :: acc
Здесь toHtmlDict
в основном остается тем же, но использует Dict.foldl
вместо Dict.map
и предоставляет ему начальное значение пустого списка, []
.
toLiDict
видит большие изменения. Его тип изменился на Int -> Int -> List (Html msg) -> List (Html msg)
, что означает, что он принимает аргументы: ключ и значение, оба из которых равны Int
с, а аккумулятор равен List (Html msg)
, как и возвращаемое значение.
Но реализация практически не изменилась. Вместо того, чтобы просто возвращать элемент напрямую, он добавляется к аккумулятору с помощью :: acc
.
И это все, что нужно сделать. Результатом сгиба является накопленный список Html
элементов, как и ожидалось. Если вы добавите приведенный выше код в свой, он будет работать.
Dict.values и Dict.toList
Наконец, ранее я заметил, что foldl
- хороший выбор, если нет более подходящей специализированной функции.А поскольку конечный результат, который вам нужен, это список, либо Dict.values
, либо Dict.toList
, как предположил @bdukes, вероятно, так оно и есть.Они не так эффективны, как фолд, так как вы будете повторять элементы дважды, один раз для преобразования в список, а затем для их отображения, но на практике это редко имеет значение.Специализированные функции также более наглядны и лучше документируют ваши намерения, поэтому используйте их, если можете.