Skip to content

Instantly share code, notes, and snippets.

@sadache
Created August 17, 2010 13:44
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sadache/529983 to your computer and use it in GitHub Desktop.
Save sadache/529983 to your computer and use it in GitHub Desktop.
// I really do not like using the syntax that removes points
scala> List("one","two") foldLeft ("") (_+_)
<console>:6: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
List("one","two") foldLeft ("") (_+_)
^
// Int ???
scala> List("one","two") foldLeft ("") ((_+_):(String,String) => String)
<console>:6: error: type mismatch;
found : (String, String) => String
required: Int
List("one","two") foldLeft ("") ((_+_):(String,String) => String)
^
scala> List("one","two").foldLeft ("") (_+_)
res2: java.lang.String = onetwo
@misto
Copy link

misto commented Aug 17, 2010

I guess it's not a bug but rather a limitation of the type inferencer. For example, you can also write it like this:

(List("one","two") foldLeft ("")) (_+_)

@sadache
Copy link
Author

sadache commented Aug 17, 2010

but you can see in the second line I tried to feed it types, didn't work either... Having foldLeft curried is to help type inference. I'd suggest it is a precedence problem. And it is quite confusing. That's why personally I prefer not to use that syntactic sugar...

@misto
Copy link

misto commented Aug 17, 2010

Hm, actually, I think it doesn't work because you can only omit the ., i.e., use the operator notation, if there are 0 or 1 arguments to the function. That would also explain why your type ascription is ignored.

@sadache
Copy link
Author

sadache commented Aug 17, 2010

there is only one argument to the foldLeft method. Then it return a function that takes the other parameter.

@misto
Copy link

misto commented Aug 17, 2010

Argh, yes of course.. I give up :-)

@deanwampler
Copy link

Is it a type inference limitation or just a case that the compiler didn't know that the (+) belonged with the foldLeft, since omitting the '.' is only supposed to work with zero or 1 argument methods? If so, then the error message wasn't very helpful as the real "error" was in deciding how to associate the parsed tokens.

@deanwampler
Copy link

Ah, you already commented on my suggestion...

@hedefalk
Copy link

I've been trying to get my head around the type inferer's behaviour around currying too. I got this from a Scheme-friend:

(reduce (lambda (x y) 
    (cons (if (null? y) 
    x 
    (+ x (car y))) y)) 
'(1 2 3) 
'())
=>
(6 5 3)

which I could translate to

 List(1, 2, 3).foldRight[List[Int]] (Nil) ((x, l) => if(l.isEmpty) List(x) else l.head + x :: l)

but I felt a bit ashamed for all the dots so as the ML fan boy I am I tried to remove them:

 scala> List(1, 2, 3) :\ (Nil : List[Int]) ((x,l) => if(l isEmpty) List(x) else (l head) + x :: l)  
 <console>:6: error: missing parameter type
       List(1, 2, 3) :\ (Nil : List[Int]) ((x,l) => if(l isEmpty) List(x) else (l head) + x :: l)
                                        ^

That error makes me want to add the parameter type to l and x in the anonymous function:

scala> List(1, 2, 3) :\ (Nil : List[Int]) ((x : Int, l : List[Int]) => if(l isEmpty) List(x) else (l head) + x :: l)
 <console>:6: error: type mismatch;
found   : (Int, scala.List[Int]) => scala.collection.immutable.List(in package immutable)[Int]
required: Int
       List(1, 2, 3) :\ (Nil : List[Int]) ((x : Int, l : List[Int]) => if(l isEmpty) List(x) else (l head) + x :: l)
                                                                ^

That obviously didn't work. It seems like the same error you got. In my example I at least mention Int so I didn't think more about it. But in your code Int is never even mention so that makes me think Int is just some kind of hacky last resort somewhere in the type inferer?

Anyway, I tried around a whole lot and finally I noticed that a parenthesis around the first function call did the trick just like in Mirkos example:

scala> (List(1, 2, 3) :\ (List[Int]())) ((x,l) => if(l isEmpty) List(x) else (l head) + x :: l)
 res5: List[Int] = List(6, 5, 3)

or maybe this one is the nicest:

 scala> (List(1, 2, 3) :\ (Nil : List[Int])) ((x,l) => if(l isEmpty) List(x) else (l head) + x :: l)
 res6: List[Int] = List(6, 5, 3)

Here I also typed Nil. The whole thing feels weird but I guess that the type inferer is doing really complex stuff. No simple Hindley–Milner here ;)

Mirko, did the underscores get lost somewhere? I need to do it like this:

scala> (List("one","two") foldLeft ("")) (_+_)
res8: java.lang.String = onetwo

I actually really LOVE point-free currying in ML but I guess the Scala one is somewhat limited and obviously makes the type inferer behave a bit weird sometimes.

@sadache
Copy link
Author

sadache commented Aug 18, 2010

I love ML currying, but this is not it and often it gets unpredictable to me. I guess there is a problem of precedence before the type inferencer kicks in. It is very confusing since it is hard to grasp even forgetting about this very case. I don't seem to be getting the mental model and that's why I tent to use it very rarely and only in places where it is clear and obvious.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment