Larry Jones
Larry Jones

Reputation: 11

Haskell String list to Int list

I have a list of strings and I want to read the strings one by one and convert it into a list of ints, is there a way to convert each character into a new list?

["123","346","789"] to [[1,2,3],[4,5,6],[7,8,9]]

stringToInt :: [String] -> [[Int]]

Upvotes: 0

Views: 1854

Answers (2)

Stéphane Laurent
Stéphane Laurent

Reputation: 84519

import Data.List (intersperse)

f :: String :: [Int]
f stringnum = read $ "[" ++ intersperse  ',' stringnum ++ "]" :: [Int]

>>> map f ["123", "456"]
[[1,2,3],[4,5,6]]

Upvotes: 1

Adam Smith
Adam Smith

Reputation: 54163

One of the pillars of functional programming is map, which has the following signature:

map :: (a -> b) -> [a] -> [b]

In other words, it takes a function that expects a value of type a and returns a value of type b (N.B. these could be the same type, but don't have to be) along with a list of a values, and kicks you back a list of b values. Take this example:

double :: Int -> Int
double = (*2)
{- equivalently written as:
   double x = x * 2 -}

as = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
bs = map double as

In this example, map is specialized where a ~ Int and b ~ Int, resolving to

map :: (Int -> Int) -> [Int] -> [Int]

and bs is then [2, 4, 6, 8, 10, 12, 14, 16, 18, 20].


Why this long primer on map? Because it's the framework to so many answers in functional programming, including your question. Remember that String is just a type synonym for [Char], so you're trying to go from [[Char]] -> [[Int]]. Gee, that sure looks like the last two terms of the type signature for map, doesn't it? Let's specialize map to operate in these terms.

map :: ([Char] -> [Int]) -> [[Char]] -> [[Int]]

But wait, the function that map is expecting also looks like the result of a mapping. Let's write that, too.

map :: (Char -> Int) -> [Char] -> [Int]

So what we want is a double map, applied to some function f such that:

map (map f) :: [[Char]] -> [[Int]]
{- more idiomatically written as
   (map . map) f :: [[Char]] -> [[Int]] -}

This means we need an f :: Char -> Int -- some function that goes from single characters to integers. There's a reasonably small number of defined inputs for that operation, so I'd just write it.

digitToInt :: Char -> Int
digitToInt '0' = 0
digitToInt '1' = 1
digitToInt '2' = 2
digitToInt '3' = 3
digitToInt '4' = 4
digitToInt '5' = 5
digitToInt '6' = 6
digitToInt '7' = 7
digitToInt '8' = 8
digitToInt '9' = 9
digitToInt 'a' = 10
digitToInt 'A' = 10
digitToInt 'b' = 11
digitToInt 'B' = 11
digitToInt 'c' = 12
digitToInt 'C' = 12
digitToInt 'd' = 13
digitToInt 'D' = 13
digitToInt 'e' = 14
digitToInt 'E' = 14
digitToInt 'f' = 15
digitToInt 'F' = 15
digitToInt _   = error "Invalid digit"

but N.B. that this function comes standard in Data.Char

import Data.Char (digitToInt)

Your result then is:

result = (map.map) digitToInt ["123","346","789"]

Upvotes: 1

Related Questions