Как преобразовать список чисел в строку без форматирования - PullRequest
0 голосов
/ 28 июня 2019

Это то, что я имею до сих пор:

toStr :: (Num a) => [a] -> String
toStr (x:xs)
    | length xs == 0 = []
    | length xs > 0 = show x : toStr xs

Я получаю эту ошибку:

* Couldn't match type `Char' with `[Char]'
  Expected type: [String]
    Actual type: String

Я не понимаю, почему он получает Char вместо [Char]. Заранее спасибо.

Для справки я пытаюсь преобразовать двоичный список [1, 0, 0, 1, 1, 0] в список, подобный этому «100110».

Ответы [ 2 ]

4 голосов
/ 28 июня 2019

Понимание проблемы

toStr :: (Num a) => [a] -> String
toStr (x:xs)
    | length xs == 0 = []
    | length xs > 0 = show x          :  toStr xs
                       ^              ^      ^
                    This is a String  |      |
                                      |  This is a String
                                   This is a function of type String -> [String] -> [String]

Итак, у вас есть:

  • show x, что является String
  • toStr xs, что является String
  • Функция :, которая ожидает String и [String].

Это несогласие по toStr xs является строкой, но ожидалось, что : быть списком строк - это суть проблемы. Вы хотели объединить ваши строки в одну строку (show x ++ toStr xs).

Понимание следующей проблемы *

Теперь у вас должно быть несколько других проблем. Во-первых, у вас есть Num a => a, который вы пытаетесь show. Функция show не является частью Num, а вместо этого входит в класс Show, поэтому измените Num a => на Show a =>.

Наконец, этот код не очень хорошо обрабатывает случай пустого списка:

 toStr (x:xs)
    | length xs == 0 = []

Заметив, что после x ничего не происходит, этот код будет игнорировать последнее значение x и вернет пустой список. Он не обрабатывает случай, когда нет «последнего элемента», и все, что у вас есть, это пустой список Чтобы справиться с этим, попробуйте toStr [] = [].

Собираем все вместе

toStr :: (Show a) => [a] -> String
toStr [] = []
toStr (x:xs) = show x ++ toStr xs

с результатом:

> toStr [1,0,0,1,1]
"10011"

Идиоматический код

Выше приведен хороший результат, но примитивные рекурсивные функции обычно не нужны при написании Haskell. Большинство операций типа данных map или fold. В этом случае это отображение функции show (обратите внимание, как она show использует каждый элемент) и fold функции ++ - также известной как конкатенация строк.

toStr2 xs = foldr (++) "" (map show xs)
-- > toStr2 [1,0,0,1,1]
-- "10011"

Даже это можно еще больше упростить. Так часто встречается специальная функция concatMap:

toStr3 xs = concatMap show xs

То, что мы можем «сократить» (убрать большинство внешних аргументов из определения / приложения функции - думайте с точки зрения определения функции как другой функции, а не значений, которые она произвела):

toStr4 = concatMap show

В качестве альтернативы, мы можем заново получить исходный глагол сгиба и карты. Функция concatMap - это просто определенный тип fold + map, который работает со списками. Существует более общий foldMap, который работает с любой функцией, которая производит моноид (и списки являются одной из таких структур, что означает, что так же как и строки, так как они являются списками символов):

toStr5 = foldMap show
1 голос
/ 28 июня 2019

Как упомянул Сергей, оператор ':' не может использоваться, потому что выражение "show x" возвращает строку, а не один символ.

Этот код ниже, кажется, делает то, что вы хотели:

toStr :: (Num a, Show a) => [a] -> String
toStr (x:xs)
    | null xs         = show x  -- avoid using length because of cost
    | not (null xs)   = (show x) ++ (toStr xs)
toStr [] = ""


main = do
    let ls1 = [ 13, 17, 19, 23 ]
    let st1 = toStr ls1
    let st2 = concatMap show ls1 -- as per melpomene's remark
    putStrLn $ "st1 = " ++ st1
    putStrLn $ "st2 = " ++ st2

В качестве дополнительного замечания, программисты на Haskell обычно избегают использования функции length , когда им просто нужно узнать, пуст ли список или нет.Если вы сделаете это, все может стать очень уродливым из-за наших потенциально неограниченных ленивых списков.

...