|
View:
New views
3 Messages
—
Rating Filter:
Alert me
|
|
|
Implicit conversion to listHi,
This is the first time I have written an implicit conversion, so I am not sure if I am making some basic implementation error, or whether the problem is conceptual. What I am trying to do is provide a uniform interface to iterating over some data in a database. So the natural approach seems to be to use list comprehensions (the flatMap monad things). In the code below you can see how this lets me easily iterate over all the tags associated with all the tracks associated with a particular artist. This works just fine while I am dealing with collections. But some methods return a single value. For example, there is only one artist for a given name. I would like to use the same list comprehension approach in this case but, of course, it doesn't work. So, I thought, why not add an implicit conversion that converts a single instance to a list? Then the single return value will be converted and everything will transparently work. However, in the code below, this does not work. class Record { implicit def asList[R <: Record](record: R): List[R] = record :: Nil } class Artist extends Record class Track extends Record class Tag extends Record class Database { def tracksForArtist(artist: Artist) = new Track :: new Track :: Nil def tagsForTrack(track: Track) = new Tag :: Nil // this is unusual, does not return a collection def artistForName(name: String) = new Artist } object M extends Application { val database = new Database // this works just fine for (track <- database.tracksForArtist(new Artist); tag <- database.tagsForTrack(track)) yield (println(tag)) // this fails to compile - no implicit conversion to a list for (artist <- database.artistForName("the beatles"); track <- database.tracksForArtist(new Artist); tag <- database.tagsForTrack(track)) yield (println(tag)) } Sorry for asking yet another question, but can anyone please explain why? Thanks, Andrew |
|
|
Re: Implicit conversion to listYour implicit conversion is not in scope of object M. This compiles and runs:
sealed trait Record case class Artist extends Record case class Track extends Record case class Tag extends Record class Database { def tracksForArtist(artist: Artist) = new Track :: new Track :: Nil def tagsForTrack(track: Track) = new Tag :: Nil // this is unusual, does not return a collection def artistForName(name: String) = new Artist } object M extends Application { implicit def asList[R <: Record](record: R): List[R] = record :: Nil val database = new Database // this works just fine def showTracks() = { for (track <- database.tracksForArtist(new Artist); tag <- database.tagsForTrack(track)) yield (println(tag)) // this fails to compile - no implicit conversion to a list for (artist <- database.artistForName("the beatles"); track <- database.tracksForArtist(new Artist); tag <- database.tagsForTrack(track)) yield (println(tag)) } } But if you want a single optional value to be returned, you better use Scala's Option class, like so: class Database { def artistForName(name: String) = Some(new Artist) } scala> for (track <- db.artistForName("the beatles")) yield println(track) res0: Option[Unit] = Some(()) That should give you what you want. Arjan
On Sat, Oct 31, 2009 at 3:09 PM, andrew cooke <andrew@...> wrote: Hi, |
|
|
Re: Implicit conversion to listah! thanks. i have too little faith in scala - i was thinking it
likely that what i wanted was impossible for some reason.... :o) 2009/10/31 Arjan Blokzijl <arjanblokzijl@...>: > Your implicit conversion is not in scope of object M. This compiles and > runs: > > sealed trait Record > > case class Artist extends Record > case class Track extends Record > case class Tag extends Record > > class Database { > def tracksForArtist(artist: Artist) = new Track :: new Track :: Nil > def tagsForTrack(track: Track) = new Tag :: Nil > // this is unusual, does not return a collection > def artistForName(name: String) = new Artist > } > > object M extends Application { > implicit def asList[R <: Record](record: R): List[R] = record :: Nil > val database = new Database > // this works just fine > def showTracks() = { > > for (track <- database.tracksForArtist(new Artist); > tag <- database.tagsForTrack(track)) > yield (println(tag)) > // this fails to compile - no implicit conversion to a list > for (artist <- database.artistForName("the beatles"); > track <- database.tracksForArtist(new Artist); > tag <- database.tagsForTrack(track)) > yield (println(tag)) > } > } > > > But if you want a single optional value to be returned, you better use > Scala's Option class, like so: > > class Database { > def artistForName(name: String) = Some(new Artist) > } > > scala> for (track <- db.artistForName("the beatles")) yield println(track) > res0: Option[Unit] = Some(()) > > That should give you what you want. > > Arjan > > > > On Sat, Oct 31, 2009 at 3:09 PM, andrew cooke <andrew@...> wrote: >> >> Hi, >> >> This is the first time I have written an implicit conversion, so I am >> not sure if I am making some basic implementation error, or whether >> the problem is conceptual. >> >> What I am trying to do is provide a uniform interface to iterating >> over some data in a database. So the natural approach seems to be to >> use list comprehensions (the flatMap monad things). In the code below >> you can see how this lets me easily iterate over all the tags >> associated with all the tracks associated with a particular artist. >> >> This works just fine while I am dealing with collections. But some >> methods return a single value. For example, there is only one artist >> for a given name. I would like to use the same list comprehension >> approach in this case but, of course, it doesn't work. >> >> So, I thought, why not add an implicit conversion that converts a >> single instance to a list? Then the single return value will be >> converted and everything will transparently work. >> >> However, in the code below, this does not work. >> >> class Record { >> implicit def asList[R <: Record](record: R): List[R] = record :: Nil >> } >> >> class Artist extends Record >> class Track extends Record >> class Tag extends Record >> >> class Database { >> def tracksForArtist(artist: Artist) = new Track :: new Track :: Nil >> def tagsForTrack(track: Track) = new Tag :: Nil >> // this is unusual, does not return a collection >> def artistForName(name: String) = new Artist >> } >> >> object M extends Application { >> val database = new Database >> // this works just fine >> for (track <- database.tracksForArtist(new Artist); >> tag <- database.tagsForTrack(track)) >> yield (println(tag)) >> // this fails to compile - no implicit conversion to a list >> for (artist <- database.artistForName("the beatles"); >> track <- database.tracksForArtist(new Artist); >> tag <- database.tagsForTrack(track)) >> yield (println(tag)) >> } >> >> Sorry for asking yet another question, but can anyone please explain why? >> >> Thanks, >> Andrew > > |
| Free embeddable forum powered by Nabble | Forum Help |