[Haskell-cafe] What does "1 = 2" mean in Haskell?

68 views
Skip to first unread message

Harendra Kumar

unread,
Feb 23, 2017, 9:06:16 PM2/23/17
to haskell-cafe
Kids have this amazing ability to break any toy in minutes. I gave my seven year old daughter ghci to play with and in a little while she said it is broken:

>> let 1 = 2

>> 1

1

>> 


Earlier, I had explained to her about symbols and assigning values to symbols, and I said numbers are not symbols. But when she came up with this I could not explain what's going on. How can "1 = 2" be a valid equation? Am I missing something fundamental here, or it is just broken?


-harendra

Brandon Allbery

unread,
Feb 23, 2017, 9:09:14 PM2/23/17
to Harendra Kumar, haskell-cafe
It's a pattern match. The match fails, but as it produced no bindings it cannot be observed and its success or failure is irrelevant. 

--
brandon s allbery kf8nh                               sine nomine associates
allb...@gmail.com                                  ball...@sinenomine.net
unix, openafs, kerberos, infrastructure, xmonad        http://sinenomine.net

Harendra Kumar

unread,
Feb 23, 2017, 9:58:27 PM2/23/17
to Brandon Allbery, haskell-cafe
My first guess was a pattern match, but it sounded a bit odd because there is no explicit constructor in case of numbers.  If there were an explicit constructor it would have been easier to imagine this as a pattern match. This seems to be a weird side effect of the special handling of numbers.

-harendra

Brandon Allbery

unread,
Feb 23, 2017, 10:02:34 PM2/23/17
to Harendra Kumar, haskell-cafe
It is, yes. (Literal numbers in patterns occasionally have unexpected type ramifications as a result; and occasionally others, since the compiler rewrites the pattern match into a guard. It's one of those things that Just Works 99% of the time and then makes you tear your hair out.)

Harendra Kumar

unread,
Feb 23, 2017, 10:13:39 PM2/23/17
to Brandon Allbery, haskell-cafe
Are pattern matches which produce no bindings useful in any case? Will it be possible or a good idea for the compiler to produce warnings in such cases? This seems to be just a no-op.

-harendra

Brandon Allbery

unread,
Feb 23, 2017, 10:21:51 PM2/23/17
to Harendra Kumar, haskell-cafe
Literally the only use I've seen for this was a CCC puzzle. However, it is the trivial case of something that is more useful: pattern matching the result of an expression (say, a Data.Map.lookup when you know the key exists).

pyanfar Z$ ghc -c -Wall Mu.hs 

Mu.hs:3:1: Warning:
    Defaulting the following constraint(s) to type ‘Integer’
      (Eq a0) arising from the literal ‘1’ at Mu.hs:3:1
      (Num a0) arising from the literal ‘1’ at Mu.hs:3:1
    In the pattern: 1
    In a pattern binding: 1 = 2

Mu.hs:3:1: Warning: This pattern-binding binds no variables: 1 = 2

Harendra Kumar

unread,
Feb 23, 2017, 10:42:26 PM2/23/17
to Brandon Allbery, haskell-cafe
On 24 February 2017 at 08:45, Brandon Allbery <allb...@gmail.com> wrote:
Literally the only use I've seen for this was a CCC puzzle. However, it is the trivial case of something that is more useful: pattern matching the result of an expression (say, a Data.Map.lookup when you know the key exists).

Can you explain how that will be useful (without a binding)? Will the pattern match be ever actually tried when there is no binding?

-harendra 

Brandon Allbery

unread,
Feb 23, 2017, 10:53:59 PM2/23/17
to Harendra Kumar, haskell-cafe
Without a binding it is useless at top level, but if you strictify the pattern it can be useful in `let` (possibly as a sanity check where you want the program to abort if it fails). I don't recall offhand if it desugars usefully in list comprehensions, but if so it would work as a filter. There may also be other specialized use cases; general syntax tends to get reused a lot in Haskell, so making this case a syntax error could make it difficult to support actually useful cases. :)

(Also I'm sure someone overly clever could figure out some way to abuse it. :)

Taeer Bar-Yam

unread,
Feb 24, 2017, 12:01:55 AM2/24/17
to Brandon Allbery, Harendra Kumar, haskell-cafe
Since nobody has provided an example use case, I will. It's not particularly useful, but it's a minimal case that does something interesting.

func :: (Int, a) -> Maybe a
func (0, x) = Just x
func _ = Nothing

Excerpts from Brandon Allbery's message of February 23, 2017 10:51 pm:

> _______________________________________________
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> Only members subscribed via the mailman list are allowed to post.

--Taeer
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.

Harendra Kumar

unread,
Feb 24, 2017, 12:05:49 AM2/24/17
to Brandon Allbery, haskell-cafe
Yes, if you use a bang pattern in a let clause it can act as an assert in a strict context (e.g. in IO Monad). But, it can't even be caught as an exception (or can it?). For example, this fails:

x = fromList [("x", 1)] :: Map String Int
main = print $ let !Nothing = Data.Map.lookup "x" x in 10

x: x.hs:22:20-51: Irrefutable pattern failed for pattern Nothing

-harendra

Harendra Kumar

unread,
Feb 24, 2017, 12:10:04 AM2/24/17
to o...@cs.otago.ac.nz, haskell-cafe
CCing the list. I guess you intended to cc but forgot.

On 24 February 2017 at 09:27, <o...@cs.otago.ac.nz> wrote:
In Erlang, the equivalent of a let fails.
1> 1=2.
** exception error: no match of right hand side value 2

In SML, the equivalent of a let fails.
- val 1 = 1;
- val 1 = 2;

uncaught exception Bind [nonexhaustive binding failure]
  raised at: stdIn:2.5-2.10

The problem is not that let 1 = 2 ... is *legal* but that
- the compiler is  *silent* about it
- the runtime is *silent* about it.
Compiling the little program

  main = let 1 = 2 in print "hi"

I expected that the compiler would be silent but that
there would be some sort of "matched failed" error at
run time.  Silly me.


The thing is, it is not just bindings that bind no variables
that act as if they were not there.

  main = let [x] = [1,2] in print "hi"

also compiles silently and runs without error.  Change it to

  main = let [x] = [1,2] in print ("hi" ++ show x)

and you get a runtime error

<object>: <source>: Irrefutable pattern failed for pattern [x].

I wish the compiler would report an error something like

"<location>: possibly failing match deleted
             because it binds no live variables"




Brandon Allbery

unread,
Feb 24, 2017, 12:13:24 AM2/24/17
to Taeer Bar-Yam, haskell-cafe

On Fri, Feb 24, 2017 at 12:00 AM, Taeer Bar-Yam <ta...@necsi.edu> wrote:
Since nobody has provided an example use case, I will. It's not particularly useful, but it's a minimal case that does something interesting.

I spent about 10 minutes trying to construct one that made any sense. :/

Brandon Allbery

unread,
Feb 24, 2017, 12:17:01 AM2/24/17
to Harendra Kumar, haskell-cafe

On Fri, Feb 24, 2017 at 12:08 AM, Harendra Kumar <harendr...@gmail.com> wrote:
I wish the compiler would report an error something like

"<location>: possibly failing match deleted
             because it binds no live variables"

Note that I showed the warning -Wall gives you earlier. -Werror also works... and, while I don't think it's in 8.0.x yet, future versions will allow selective conversions of warnings to errors.

Jeff Clites

unread,
Feb 24, 2017, 12:24:05 AM2/24/17
to haskell-cafe
This works too:

    Nothing = Just "hello"

so you get the same effect even without any literal number specialness.

Even this:

    Just x = Nothing

also "works" until you force evaluation of x, as an irrefutable (lazy) pattern match. So in a way, you could view the first case as a lazy pattern match in which there is nothing you could possibly force, so there's no way to manifest the pattern match failure.

Just another way of looking at it.

JEff
_______________________________________________

Harendra Kumar

unread,
Feb 24, 2017, 12:30:13 AM2/24/17
to Taeer Bar-Yam, haskell-cafe
Pattern match in a function definition is different. Here the pattern match is actually being used as part of the function definition.  We were trying to figure out the usefulness of non-function pattern matches which do not result in a binding. The assert case pointed out by Brandon is one example. Though not so useful.

-harendra

Harendra Kumar

unread,
Feb 24, 2017, 12:40:57 AM2/24/17
to Jeff Clites, haskell-cafe
In these examples, we can identify the constructor (capitalized first letter) on the LHS and so we are trained to know that it is a pattern match. The original point related to number specialness was that "1 = 2" is not easily identifiable as a pattern match because there are no explicit constructors. The literal "1" here is neither an "explicit constructor" nor a binding symbol.

-harendra

Brandon Allbery

unread,
Feb 24, 2017, 12:50:29 AM2/24/17
to Harendra Kumar, haskell-cafe

On Fri, Feb 24, 2017 at 12:38 AM, Harendra Kumar <harendr...@gmail.com> wrote:
In these examples, we can identify the constructor (capitalized first letter) on the LHS and so we are trained to know that it is a pattern match. The original point related to number specialness was that "1 = 2" is not easily identifiable as a pattern match because there are no explicit constructors. The literal "1" here is neither an "explicit constructor" nor a binding symbol.

Yes, at this point you just have to know that the Report specifies a bunch of special handling for numeric literals.

Jeff Clites

unread,
Feb 24, 2017, 1:00:25 AM2/24/17
to haskell-cafe
On Feb 23, 2017, at 9:49 PM, Brandon Allbery <allb...@gmail.com> wrote:

On Fri, Feb 24, 2017 at 12:38 AM, Harendra Kumar <harendr...@gmail.com> wrote:
In these examples, we can identify the constructor (capitalized first letter) on the LHS and so we are trained to know that it is a pattern match. The original point related to number specialness was that "1 = 2" is not easily identifiable as a pattern match because there are no explicit constructors. The literal "1" here is neither an "explicit constructor" nor a binding symbol.

Yes, at this point you just have to know that the Report specifies a bunch of special handling for numeric literals.

Also:  "day" = "night"

Isn't every "=" a pattern match?

JEff

Harendra Kumar

unread,
Feb 24, 2017, 1:24:23 AM2/24/17
to Jeff Clites, haskell-cafe
Every "=" with a constructor on the LHS. String is also a special case similar to numeric literals. The above example should be equivalent to:

'd' : 'a' : 'y' : [] = "night"

-harendra

Taeer Bar-Yam

unread,
Feb 24, 2017, 2:09:24 AM2/24/17
to Brandon Allbery, Harendra Kumar, haskell-cafe
I think the usefulness of numeric / string literals as pattern matches is as
part of larger matches (as someone mentioned), not by itself. But since (I
assume) these things are defined recursively, it makes sense just to add it as a
base-level pattern match.

Furthermore, you would not want
```
main = let 1 = 2 in print "foo"
```
to error, since the pattern match is unused, and haskell is a lazy language.
Really, though, we probably shouldn't be putting incomplete pattern matches in
our code :P

--Taeer

Dan Burton

unread,
Feb 24, 2017, 6:25:28 PM2/24/17
to Taeer Bar-Yam, haskell-cafe
Note that similar to the !Nothing example, a bang pattern surfaces the error you'd expect

Prelude> :set -XBangPatterns
Prelude> let !1 = 2
*** Exception: <interactive>:2:5-10: Irrefutable pattern failed for pattern 1

So this exception is lurking about, but due to laziness and the equation's irrelevance, it doesn't show unless you force it with strictness.

I think the real expectation mismatch here is that numbers are not bindable symbols, so `let 1 = expr in 1` does not rebind 1 to be `expr` like a beginner might think.

-- Dan Burton

Alexey Muranov

unread,
Feb 25, 2017, 9:32:45 AM2/25/17
to Haskell-cafe, haskel...@haskell.org, harendr...@gmail.com
Just to link this to a previous discussion of this topic:

  https://groups.google.com/d/msg/haskell-cafe/2zpIvI0IBSc/MuHmTEUiswUJ

Alexey.

Yawar Amin

unread,
Feb 25, 2017, 1:59:58 PM2/25/17
to Haskell-cafe, allb...@gmail.com, haskel...@haskell.org, harendr...@gmail.com
Hi,


On Thursday, February 23, 2017 at 10:13:39 PM UTC-5, Harendra Kumar wrote:
Are pattern matches which produce no bindings useful in any case?

They  are useful in the case of trying to get GHC to tell you the type of something by deliberately giving it a wrong type:

λ let () = 1 in 2
Could not deduce (Num ()) arising from the literal ‘1’
from the context (Num a)
bound by the inferred type of it :: Num a => a at <interactive>:1:1
In the expression: 1
In a pattern binding: () = 1
In the expression: let () = 1 in 2

Cheers

Alexey Muranov

unread,
Feb 25, 2017, 5:58:28 PM2/25/17
to Haskell-cafe, harendr...@gmail.com, haskel...@haskell.org, allb...@gmail.com
It seems weird however that Haskell allows

  let 1 = 0

but does not allow

  let (f x, g y z) = (x*x, y*z)

Alexey.

David Feuer

unread,
Feb 25, 2017, 6:25:17 PM2/25/17
to Harendra Kumar, haskel...@haskell.org
I firmly believe that making pattern matches in let and where clauses lazy by default was a mistake in the Haskell Report. It's inconsistent with how pattern matching works elsewhere in the language, and also makes a strange distinction between outer and inner pattern matches. Unfortunately, it's way too late to fix that mistake.

Alexey Muranov

unread,
Feb 25, 2017, 7:08:58 PM2/25/17
to Haskell-cafe, harendr...@gmail.com, haskel...@haskell.org, david...@gmail.com
Can be added to Nitpicks then :) :

  https://wiki.haskell.org/Nitpicks

Alexey.

Ivan Lazar Miljenovic

unread,
Feb 25, 2017, 10:29:47 PM2/25/17
to David Feuer, Haskell Cafe
On 26 February 2017 at 10:23, David Feuer <david...@gmail.com> wrote:
> I firmly believe that making pattern matches in let and where clauses lazy
> by default was a mistake in the Haskell Report. It's inconsistent with how
> pattern matching works elsewhere in the language, and also makes a strange
> distinction between outer and inner pattern matches. Unfortunately, it's way
> too late to fix that mistake.

I've used that though in combination of guards where I call the
(lazily evaluated) result only in cases where it's irrefutable.

--
Ivan Lazar Miljenovic
Ivan.Mi...@gmail.com
http://IvanMiljenovic.wordpress.com

David Feuer

unread,
Feb 25, 2017, 11:44:46 PM2/25/17
to Ivan Lazar Miljenovic, Haskell Cafe
Yes, lazy patterns are useful. That's what we have the ~ syntax for!
You can always write

where
~(a, b) = ....

or whatever. I think a bang is good for a strict non-pattern binding, like

where
!a = ....

because that's the unusual case, but I think it's bad for a strict
pattern binding, which is the *usual* case.

o...@cs.otago.ac.nz

unread,
Feb 26, 2017, 6:35:26 PM2/26/17
to Taeer Bar-Yam, haskell-cafe
>
> Furthermore, you would not want
> ```
> main = let 1 = 2 in print "foo"
> ```
> to error, since the pattern match is unused, and haskell is a lazy
> language.

That's not at all clear. In fact, I believe this thread exists
because the OP's daughter expected that it WOULD raise an error.

For what it's worth,
Start = let 1 = 2 in "hello"
is rejected by the Clean compiler, even though Clean is much
like Haskell, and 1 is otherwise allowed as a pattern.

If nothing else, it would be nice to have a "dead code" warning
from the compiler about code that is certain not to be evaluated.
"2" counts as dead code in this example.

Brandon Allbery

unread,
Feb 26, 2017, 6:38:04 PM2/26/17
to Richard O'Keefe, haskell-cafe

On Sun, Feb 26, 2017 at 6:34 PM, <o...@cs.otago.ac.nz> wrote:
If nothing else, it would be nice to have a "dead code" warning
from the compiler about code that is certain not to be evaluated.
"2" counts as dead code in this example.

I did point out that -Wall includes a warning for this earlier... and "dead code" warnings in most compilers require optimization.

Alexey Muranov

unread,
Feb 27, 2017, 1:51:29 AM2/27/17
to Haskell-cafe, ta...@necsi.edu, haskel...@haskell.org, o...@cs.otago.ac.nz
On Monday, February 27, 2017 at 12:35:26 AM UTC+1, o...@cs.otago.ac.nz wrote:
>
> Furthermore, you would not want
> ```
> main = let 1 = 2 in print "foo"
> ```
> to error, since the pattern match is unused, and haskell is a lazy
> language.

That's not at all clear.  In fact, I believe this thread exists
because the OP's daughter expected that it WOULD raise an error.


 I think i agree with this. IMO it should raise an error as well as

  (\1 -> "hello") 2

does.

Alexey.
Reply all
Reply to author
Forward
0 new messages