Home > Enterprise >  Haskell: Non type-variable argument
Haskell: Non type-variable argument

Time:05-17

everyone! I've been learning Haskell through this lecture series and I'm trying to work through the exercises for lecture 1 (linked in the description of the video). I'm having trouble with the following exercise:

{- | Implement a function that takes a string, start and end positions
and returns a substring of a given string from the start position to
the end (including).

>>> subString 3 7 "Hello, world!"
"lo, w"

>>> subString 10 5 "Some very long String"
""

This function can accept negative start and end position. Negative
start position can be considered as zero (e.g. substring from the
first character) and negative end position should result in an empty
string.
-}

subString start end str = error "TODO"

The implementation I tried is this:

subString :: Int -> Int -> [a] -> [a]
subString start end str
    | end < 0 = []
    | start < 0 = subString 0 end str
    | otherwise = take ((end - start)   1) (drop start str)

This gives the expected results for the tests included in the comment before the function (subString 3 7 "Hello, world!" appropriately gives "lo, w" and subString 10 5 "Some very long String" appropriately gives ""). But the comment also says that it should work for negative values of start and end, which is why I included guards to specify the expected behavior for negatives. However, when I load the module in ghci and call subString -1 4 "Hello, world", I get this error:

<interactive>:25:1: error:
    • Non type-variable argument
        in the constraint: Num (t -> [Char] -> Int -> Int -> [a] -> [a])
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        it :: forall t a.
              (Num t, Num (t -> [Char] -> Int -> Int -> [a] -> [a]),
               Num (Int -> Int -> [a] -> [a])) =>
              Int -> Int -> [a] -> [a]

For the most part, I've found Haskell error messages to be far more helpful than in other languages I've learned/tried learning, but this message is complete nonsense to me. What is going on here?

(Note: at this stage in my process of learning Haskell, I don't care if the way I wrote this function is unidiomatic. I just want to get it working as intended.)

CodePudding user response:

Negative literals usually need to be surrounded by parentheses:

subString (-1) 4 "Hello, world"

Otherwise the - is parsed as an infix subtraction operator:

(subString) - (1 4 "Hello, world")

...which rarely typechecks and even more rarely makes sense. As a corollary, if you want an operator section that omits the first argument to -, you can't use the syntax (-1); instead, use subtract 1 (perhaps parenthesized if necessary).

  • Related