Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

example seq 10 | hawk -ad 'L.takeWhile (/="7") . L.dropWhile (/="3")' fails with Couldn't match type ‘B.ByteString’ with ‘Char’ #229

Closed
bwagner opened this issue May 21, 2020 · 7 comments
Labels
Milestone

Comments

@bwagner
Copy link

bwagner commented May 21, 2020

When following the examples in the README and running:

seq 10 | hawk -ad 'L.takeWhile (/="7") . L.dropWhile (/="3")'

I get the error:

error: Won't compile:
	user expression:1:16: error:
    • Couldn't match type ‘B.ByteString’ with ‘Char’
        arising from the literal ‘"7"’
    • In the second argument of ‘(/=)’, namely ‘"7"’
      In the first argument of ‘takeWhile’, namely ‘(/= "7")’
      In the first argument of ‘(.)’, namely ‘takeWhile (/= "7")’

There's a similar case posted on stackoverflow.

I'm using hawk version 1.1.1 on OS X 10.14.6.

@gelisam
Copy link
Owner

gelisam commented May 22, 2020

Thanks for reporting this! I have a test case which makes sure this example works as expected, but I've had to disable it, not because it failed with the error message you encountered, but because the environment in which the test suite is run has changed subtly over the years, causing tests which were previously succeeding to fail even though the code didn't change. For that reason, I have been reluctant to release a new version, as without tests, I didn't have much confidence that there were no regressions. Thanks for confirming that there has indeed been a regression!

@gelisam gelisam added the bug label May 22, 2020
@gelisam gelisam added this to the 1.1.2 milestone May 22, 2020
@gelisam
Copy link
Owner

gelisam commented May 22, 2020

Despite the similarity in the error messages, the stackoverflow post is about a completely different problem.

ByteString and [Char] (aka String) are two different representations for strings, hawk is using ByteString’, but the default is String`. I am thus guessing that the default is still in place even though it shouldn't. Let's see:

$ hawk '"foo"'
foo
$ hawk '"foo" :: String'
foo
$ hawk '"foo" :: B.ByteString'
foo

Nope, that's not it, the OverloadedStrings language pragma seems to be correctly picked up.

@gelisam
Copy link
Owner

gelisam commented May 22, 2020

Wait, the error message isn't complaining about B.ByteString vs [Char], it's complaining about B.ByteString and Char. That's pretty suspicious. What is the type of the overall expression?

$ hawk -ad _
...
• Found hole: _ :: [[B.ByteString]] -> a0
...

$ ghci ~/.hawk/prelude.hs
λ> :t L.takeWhile (/="7") . L.dropWhile (/="3")
L.takeWhile (/="7") . L.dropWhile (/="3") :: [[Char]] -> [[Char]]

Aha! If we ignore the difference between ByteString and [Char] for a moment and just use String for both, we see that the problem is that hawk expects a function of type [[String] -> _, but we provide it with a function of type [String] -> _. Since that example used to work, hawk definitely used to expect a function of type [String] -> _. So that's the regression.

@gelisam
Copy link
Owner

gelisam commented May 22, 2020

The first example,

> seq 3 | hawk -a 'L.reverse'
3
2
1

works just fine. That means -a is working fine, it used to and still does expect a function of type [[String]] -> _. So it's the -d which is broken. This is the flag which sets the field delimiter. It works fine when set to a non-empty string:

$ echo "1 2 3" | hawk -a -d' ' 'fmap L.reverse'
3 2 1
$ echo "1:2:3" | hawk -a -d':' 'fmap L.reverse'
3:2:1
$ echo "1, 2, 3" | hawk -a -d', ' 'fmap L.reverse'
3, 2, 1

And it correctly distinguishes between the default (an arbitrary amount of whitespace) and a single space character:

$ echo "1  2 3" | hawk -a 'fmap L.reverse'
3 2 1
$ echo "1  2 3" | hawk -a -d' ' 'fmap L.reverse'
3 2  1

But if we set it to the empty string, it's supposed to not split the lines into fields (thus causing the input to have type [String] instead of [[String]]), but it looks like it's instead behaving like the default:

$ echo "1 2  3" | hawk -a -d'' 'fmap L.reverse'
3 2 1

@gelisam
Copy link
Owner

gelisam commented May 22, 2020

The code which represents these possibilities uses Whitespace for the default behaviour, Separator ":" for -d':', but Separator "" for -d'' even though that's a special "do not split" value. I think it would be less error-prone to have a dedicated constructor for that case.

@gelisam
Copy link
Owner

gelisam commented May 22, 2020

Rewriting the parsing code to use a dedicated DoNotSeparate constructor fixed it! There was one failing test:

$ echo "x1*y1*z1 + x2*y2*z2" | hawk -D -a "\\x -> ('a', x, 'b')"
a x1*y1*z1 + x2*y2*z2 b

now outputs

$ echo "x1*y1*z1 + x2*y2*z2" | hawk -D -a "\\x -> ('a', x, 'b')"
a
x1*y1*z1 + x2*y2*z2
b

But since without the -D, we get

$ hawk "('a', \"x1*y1*z1 + x2*y2*z2\", 'b')"
a
x1*y1*z1 + x2*y2*z2
b

I think the new behaviour makes more sense.

@gelisam
Copy link
Owner

gelisam commented May 23, 2020

Fixed by #230

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants