2014-11-23 4 views
0

Я пишу функцию для преобразования списка String (считанного из файла CSV) в список парных разрядов. Это дает мне ошибку в 3-й строке.Преобразуйте список [String] в список [Double] в Haskell

stringToDouble :: [String] -> [Double] 
stringToDouble [] = error "empty list" 
stringToDouble [x] = read x :: Double -- the `read` gives me an error 
stringToDouble (x:xs) = stringToDouble xs 

Это потому, что я не помещаю преобразованное Двойное в список, который необходимо вернуть?

ответ

8

Ошибка возникает из-за того, что read x имеет тип Double, а не [Double], но в его нынешнем виде ваша функция не будет работать должным образом даже с этим исправлением.

Давайте возьмем вашу функцию и поместим ее в слова: «Возьмите передний элемент списка строк, прочитайте его как двойной, а затем сделайте то же самое с остальной частью списка». Теперь давайте посмотрим на вашу функцию:

stringToDouble :: [String] -> [Double] 
stringToDouble [] = error "empty list" 
stringToDouble [x] = read x :: Double -- Error 
stringToDouble (x:xs) = stringToDouble xs 

Теперь давайте применим исправление к нему. Кроме того, нет причин для ошибки в пустом списке; просто введите и пустой список парных:

stringToDouble :: [String] -> [Double] 
stringToDouble [] = [] 
stringToDouble [x] = [read x :: Double] -- Put the single value into a list 
stringToDouble (x:xs) = stringToDouble xs 

Проблема заключается в рекурсивном шаге. Вызов stringToDouble в списке совпадает с вызовом stringToDouble в хвосте списка. Первый элемент просто отбрасывается. Вы хотите преобразовать голову и вернуть ее обратно в список.

stringToDouble :: [String] -> [Double] 
stringToDouble [] = [] 
stringToDouble [x] = [read x :: Double] -- Put the single value into a list 
stringToDouble (x:xs) = (read x :: Double) : stringToDouble xs 

Где (:) оператор используется для прикрепления элемента к передней части списка. И при этом средняя линия даже не нужна, поскольку рекурсивный шаг будет обрабатывать преобразование, а пустой шаг списка будет обрабатывать условие остановки.

stringToDouble :: [String] -> [Double] 
stringToDouble [] = [] 
stringToDouble (x:xs) = (read x :: Double) : stringToDouble xs 

Теперь реально, вы могли бы, вероятно, удалить :: Double часть и Haskell бы понять, что вы имели в виду с ограничением по типу функции, но это не повредит, и иногда помогает читаемость покинуть его in.

+0

Большое спасибо за объяснение. Что вы предлагаете, если у меня есть список вроде этого? ["A", "1.2"] '..как я могу использовать только числа, а не слова, чтобы игнорировать «а»? Может быть, по регулярному выражению? – letsjak

+0

Что значит «проигнорировано»? Что вы хотите, чтобы не цифры? Вы не можете иметь гетерогенный список в Haskell, так что у вас не может быть, например, ["a", 1.2], поскольку он не имеет допустимого типа. –

+4

Если целью является игнорировать значения, которые невозможно прочитать, тогда определите 'readMaybe x = case читает x of {[(y," ")] -> Just y; _ -> Nothing} 'и' stringToDouble = catMaybes. карта readMaybe' – user2407038

1

Вы правы - read x :: Double имеет тип Double, в то время как тип возвращаемого значения функции типа [Double] (что означает «список Double»).

Что-то вроде этого:

stringToDouble [x] = [read x :: Double] 

должен работать.

Обратите внимание, что если вы пытаетесь преобразовать каждый элемент списка самостоятельно, вы должны написать свою функцию, используя map, вместо использования явной рекурсии. Если f имеет тип String -> Double, то map f будет функцией типа [String] -> [Double].

+0

Если я это сделаю, он печатает только первый элемент. 'stringToDouble (x: xs) = stringToDouble xs' не выполняется. – letsjak

+1

Ваша текущая функция вызывает только' read' в последнем элементе списка: если список содержит более одного элемента, он игнорирует первый. Возможно, вы имели в виду что-то вроде 'stringToDouble (x: xs) = читать x: stringToDouble xs' в третьем случае? – Benesh

+0

@letsjak Выполняется (для списков, содержащих более одного элемента), но все, что он делает, это рекурсия на хвосте. – sepp2k

Смежные вопросы