9

The following two functions are extremely similar. They read from a [String] n elements, either [Int] or [Float]. How can I factor the common code out? I don't know of any mechanism in Haskell that supports passing types as arguments.

readInts n stream = foldl next ([], stream) [1..n]
  where
    next (lst, x:xs) _ = (lst ++ [v], xs)
      where
        v = read x :: Int

readFloats n stream = foldl next ([], stream) [1..n]
  where
    next (lst, x:xs) _ = (lst ++ [v], xs)
      where
        v = read x :: Float

I am at a beginner level of Haskell, so any comments on my code are welcome.

3
  • 2
    You don't need to fold here, you can get by with a simple map. e.g. map read stream :: [Int] Also you may want to look into why you want to use foldr in Haskell rather than foldl. Commented Apr 6, 2012 at 10:37
  • 1
    @EdwardKmett Thanks for your suggestion. What I really want is to read only first n elements, and return the list and the rest of the stream. I was super sleepy yesterday, and couldn't think through. I think you want to say that with foldr I can use the constructor : directly right? I later rewrote it as (map read firstn, rest) where (firstn, rest) = splitAt n stream, quite similar to what you suggested. Commented Apr 6, 2012 at 15:11
  • You do not need to nest where; you can put next (lst, x:xs) _ = ... and v = ... in consecutive lines. Commented Apr 15, 2012 at 12:23

2 Answers 2

16

Haskell supports a high degree of polymorphism. In particular

readAny n stream = foldl next ([], stream) [1..n]
  where
    next (lst, x:xs) _ = (lst ++ [v], xs)
      where
        v = read x 

has type

readAny :: (Enum b, Num b, Read a) => b -> [String] -> ([a], [String])

thus

readInts :: (Enum b, Num b) => b -> [String] -> ([Int], [String])
readInts = readAny

readFloats :: (Enum b, Num b) => b -> [String] -> ([Float], [String])
readFloats = readAny

you dont need to specialize the type. Haskell will automatically infer the most general type possible, and the readAny here will do what you want.

It is not possible to pass types as arguments in Haskell. Rarely would you need to. For those few cases where it is necessary you can simulate the behavior by passing a value with the desired type.

Haskell has "return type polymorphism" so you really shouldn't worry about "passing the type"--odds are that functions will do what you want without you telling them to.

Sign up to request clarification or add additional context in comments.

5 Comments

Ironically, passing the type is in some implementation dependent way what happens behind the scenes, hence the question is not that far off the mark ....
Many implementations dont so much pass the type as pass a type consistent witness for the type-class values. Something like id doesn't need to know the type of its arguments at all (so long as everything is the same size)
That's what I meant with implementation dependent way. But id, having no constraints, gets passed nothing at all, I guess. The type guarantees that id is not going to do anything with it's argument that would need more information than just "it's some value", but this should be implied.
Just for any future readers that may see this question, there is a way to pass explicit type parameters. You can set -XTypeApplications and use read @T to request that read be instantiated at the explicitly given type T. This works with -XScopedTypeVariables and -XPartialTypeSignatures, too.
is it perhaps readInts :: Int -> [String] -> ([Int], [String]) (and similar for readFloats)?
9

Basically what you want is to not explicitly declare the type. Instead, defer declaring the type and let the inference engine take over for you. Also, I think you are conflating fold with map. This is how I would approach it.

readList' :: Read a => [String] -> [a]
readList' = map read


ints = readList' ["1", "2"] :: [Int] -- [1, 2]

floats = readList' ["1.0", "2.0"] :: [Float] -- [1.0, 2.0]

To read only n things from the stream, use take

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.