Reputation: 33
I'm using the mysql-haskell library, and the result of a query has the type [MySQLValue]
.
This itself is a sum type, wrapping various data types from the database into their Haskell equivalent.
I'd like to "iterate" through this list, using a function for each element to transform the MySQLValue into what I want, and then supply each element in turn into a data constructor for my in-code representation of the data.
However, that would obviously require each function to have a different type (MySQLValue -> Int
vs MySQLValue -> Text
), so I can't just use a list.
What is the elegant way of doing what I need? At the moment I'm doing it very manually like this:
data OpenWord = OpenWord
{ russian :: Maybe T.Text,
wordType :: Maybe WordType,
audio_link :: Maybe T.Text,
usage_note :: Maybe T.Text,
level :: Maybe T.Text
}
stripText :: MySQLValue -> Maybe T.Text
wordTypeFromSql :: MySQLValue -> Maybe WordType
openWordFromRow :: [MySQLValue] -> OpenWord
openWordFromRow row = OpenWord ( stripText $ row !! 0) ( wordTypeFromSql $ row !! 1)
( stripText $ row !! 2) ( stripText $ row !! 3) ( stripText $ row !! 4)
I understand I'm in a bit of a non-typesafe land, I'm mostly looking for more convinience rather than more correctness.
Upvotes: 3
Views: 176
Reputation: 476544
You can use pattern matching to unwrap the list:
openWordFromRow :: [MySQLValue] -> OpenWord
openWordFromRow (xa : xb : xc : xd : xe : _) = OpenWord (stripText xa) (wordTypeFromSql xb) (stripText xc) (stripText xd) (stripText xe)
We can use the lens
package to perform the same mapping over all elements of a tuple, and thus guarantee that the result is a tuple with the same number of elements:
import Control.Lens.Each(each)
import Control.Lens.Lens((&))
import Control.Lens.Setter((%~))
openWordFromRow :: [MySQLValue] -> OpenWord
openWordFromRow (xa : xb : xc : xd : xe : _) = OpenWord ya (wordTypeFromSql xb) yc yd ye
where (ya, yc, yd, ye) = (xa, xc, xd, xe) & each %~ stripText
or as @JonPurdy says:
import Control.Lens.Combinators(over)
import Control.Lens.Each(each)
openWordFromRow :: [MySQLValue] -> OpenWord
openWordFromRow (xa : xb : xc : xd : xe : _) = OpenWord ya (wordTypeFromSql xb) yc yd ye
where (ya, yc, yd, ye) = over each stripText (xa, xc, xd, xe)
Upvotes: 3