Creating empty list of custom type

2,584 views
Skip to first unread message

Toby Corkindale

unread,
Oct 24, 2012, 7:52:55 PM10/24/12
to Scala Melbourne
Hi,
I had a problem with my Scala syntax last night.
I'll create a demonstration example below; what it is doing is
meaningless. The problem is that I need to specify an empty list of
type Thingy as the initial parameter to foldLeft -- but I couldn't get
this to work. (However I could get it to work if I substituted the
full type definition instead of the word Thingy, but I'm sure there's
a right way to do it).

I know I can create an empty Thingy list like this:
val foo: Thingy = Nil
But I can't work out how to create an *anonymous* empty Thingy list.


type Thingy = List[ ( Char, List[Int] ) ]

def flibble(c: Char): List[Int] = List(1,2,3)

def reduceMe(input: List[Char]): Thingy =
input.foldLeft( Thingy() ) ( (acc, cur) => (cur, flibble(cur)) :: acc )

I get error: not found: value Thingy
Which is probably because it's thinking it's a variable or function, not a type.

I can create a workaround like so:
def emptyThingy: Thingy = Nil
def reduceMe(input: List[Char]): Thingy =
input.foldLeft( emptyThingy ) ( (acc, cur) => (cur, flibble(cur)) :: acc )


Anyway, would someone mind illuminating me?

thanks!
Toby



--
Turning and turning in the widening gyre
The falcon cannot hear the falconer
Things fall apart; the center cannot hold
Mere anarchy is loosed upon the world

Bernie Pope

unread,
Oct 24, 2012, 8:04:30 PM10/24/12
to scala...@googlegroups.com
Hi Toby,

My Scala syntax is rusty, but I assume Thingy, as you have written it, is just a type synonym, an I'm guessing that type synonyms in Scala don't have their own constructors.

So I presume you could have just written:

def reduceMe(input: List[Char]): Thingy =
input.foldLeft( Nil ) ( (acc, cur) => (cur, flibble(cur)) :: acc )

I haven't tried it out because I don't have Scala on my computer. The type of Nil should be a more general instance of Thingy, so Scala's type inference (as bad as it is) should be able to unify the two types.

Cheers,
Bernie.

Ben Hutchison

unread,
Oct 24, 2012, 8:14:30 PM10/24/12
to scala...@googlegroups.com
Here's 2 ways you can do it:

scala> class Thingy
defined class Thingy

scala> List[Thingy]()
res0: List[Thingy] = List()

scala> List.empty[Thingy]
res1: List[Thingy] = List()

-Ben

--
You received this message because you are subscribed to the Google Groups "Melbourne Scala User Group" group.
To post to this group, send an email to scala...@googlegroups.com.
To unsubscribe from this group, send email to scala-melb+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scala-melb?hl=en-GB.


Ken Scambler

unread,
Oct 24, 2012, 8:15:19 PM10/24/12
to scala...@googlegroups.com
Two things:
The creation method of List sits on the `List` object.  You can't call methods on a type; if you want the List construction and pattern matching behaviour you need to also do
val Thingy = List

Also, since Nil is typed as List[Nothing], it is almost useless for folds, which won't allow you to widen the element type as you go.  You need use one of:
List[MyThing]()
List.empty[MyThing]

--

Toby Corkindale

unread,
Oct 24, 2012, 8:15:22 PM10/24/12
to scala...@googlegroups.com
On 25 October 2012 11:04, Bernie Pope <bjp...@unimelb.edu.au> wrote:
> def reduceMe(input: List[Char]): Thingy =
> input.foldLeft( Nil ) ( (acc, cur) => (cur, flibble(cur)) :: acc )

That gives an error:
error: type mismatch;
found : List[(Char, List[Int])]
required: scala.collection.immutable.Nil.type
input.foldLeft( Nil ) ( (acc, cur) => (cur, flibble(cur)) :: acc )

There is then a market pointing to the :: in the line above. ie. I
think it's saying that it can't figure out how to do:
('a', List(1,2)) :: Nil

-T

Bernie Pope

unread,
Oct 24, 2012, 8:26:16 PM10/24/12
to scala...@googlegroups.com
Thanks Ken,

Goes to show that I shouldn't assume things about Scala's type system without trying it out.

This example strikes me as a lot of trouble for something that ought to be simple.

Cheers,
Bernie.

Toby Corkindale

unread,
Oct 24, 2012, 8:28:28 PM10/24/12
to scala...@googlegroups.com
On 25 October 2012 11:26, Bernie Pope <bjp...@unimelb.edu.au> wrote:
> Thanks Ken,
>
> Goes to show that I shouldn't assume things about Scala's type system without trying it out.
>
> This example strikes me as a lot of trouble for something that ought to be simple.

I'm glad I'm not the only one who was thinking this was harder than it
should be!

Toby Corkindale

unread,
Oct 24, 2012, 8:31:20 PM10/24/12
to scala...@googlegroups.com
On 25 October 2012 11:14, Ben Hutchison <brhut...@gmail.com> wrote:
> Here's 2 ways you can do it:
>
> scala> class Thingy
> defined class Thingy
>
> scala> List[Thingy]()
> res0: List[Thingy] = List()
>
> scala> List.empty[Thingy]
> res1: List[Thingy] = List()

Thanks Ben,
Could you clarify something for me though?

In your example, are you doing away with the type I created (thingy)
altogether, or just extending it info having an associated class as
well?

It's just that my type Thingy was already a List, but then you're
passing it into a list above, which I think means you'd end up with:

type Thingy = List[ ( Char, List[Int] ) ]
List[Thingy] = List() === List[List[(Char,List[Int])]] ???

Toby Corkindale

unread,
Oct 24, 2012, 8:35:42 PM10/24/12
to scala...@googlegroups.com
Would it be better to do something like this?

type subThing = (Char, List[Int])
type thingyList = List[subThing]
val foo: thingyList = List[subThing]()


That works to create an empty list of subThings, but... it requires
the coder to understand what thingyLists really consist of. ie. you
need to know more about the type than seems necessary.
It does seem to work though.

Ken Scambler

unread,
Oct 24, 2012, 8:36:52 PM10/24/12
to scala...@googlegroups.com
I tend to agree; I've memorised the formula because I've hit the same thing as Toby, but it's frustrating we can't just do (Nil /: foos)(_ blah _).

For this reason it's a good idea when defining a Empty or Null object to give it the expected type out of the box, rather than as a separate object with its own type.

So:
object Foo {
  val empty: Foo = new Foo()
}
Not
object EmptyFoo extends Foo


On 25 October 2012 11:26, Bernie Pope <bjp...@unimelb.edu.au> wrote:

Ben Hutchison

unread,
Oct 24, 2012, 9:10:00 PM10/24/12
to scala...@googlegroups.com
Yes, that's a better way. Prefer that pattern.

"type Thingy = List[(Char, List[Int])]" is creating a *type-level alias* only. Its not a value and you can't invoke methods/constructors upon it.

-Ben

Andrew Conway

unread,
Oct 24, 2012, 11:00:34 PM10/24/12
to scala...@googlegroups.com

Nil:Thingy is an anonymous empty list of type Thingy.

Running in the interpreter:


> type Thingy = List[ ( Char, List[Int] ) ]

defined type alias Thingy



> def flibble(c: Char): List[Int] = List(1,2,3)

flibble: (c: Char)List[Int]


> Nil:Thingy

res0: Thingy = List()


> def reduceMe(input: List[Char]): Thingy =   input.foldLeft( Nil:Thingy) ( (acc, cur) => (cur, flibble(cur)) :: acc )

reduceMe: (input: List[Char])Thingy



Regards,

Andrew.

Tony Morris

unread,
Oct 25, 2012, 1:15:55 AM10/25/12
to scala...@googlegroups.com

Monoid[Thingy].id

Toby Corkindale

unread,
Oct 25, 2012, 1:24:20 AM10/25/12
to scala...@googlegroups.com
On 25 October 2012 16:15, Tony Morris <tonym...@gmail.com> wrote:
> Monoid[Thingy].id

error: not found: value Monoid
(tested on Scala 2.9.2. Is that a 2.10 feature?)

Ken Scambler

unread,
Oct 25, 2012, 2:14:39 AM10/25/12
to scala...@googlegroups.com
It's in Scalaz.

A Monoid describes a combining operation and an identity value on a type; Nil/:: form a Monoid, as do Seq()/++, ""/+, 1/*, 0/+, false/||, true/&& and others.

Tony is pointing out that the folding and reducing code in this thread can all be written at this layer of abstraction without being specific to List.

Reply all
Reply to author
Forward
0 new messages