using Try monad
Mar. 12th, 2014 05:20 pm
def using[T](file:File)(f: FileInputStream => T): Try[T] = Try {
val in = new FileInputStream(file)
(Try(f(in)), Try(in.close))._1
}.flatten
def startsWith(prefix: Array[Byte])(file: File):Boolean =
using (file) (in => prefix forall (in.read ==)) filter identity isSuccess
What happens here. I want to check if a file starts with these bytes (usually, "%PDF".getBytes).
I have function
using that takes a file, then takes a function that converts a stream into something, opens the file, feeds the stream to the function, then always closes the file, returning a failure something went wrong.In startsWith I get a prefix and a file; on this file I call the function that reads the stream and compares its bytes with the bytes of prefix; the result will be Try[Boolean]; I filter it, so that Success(false) will turn into Failure; then I check if it's still a success.
Obvious and funny; and yes, we use Java io library here, unfortunately.
introduced a constant
Mar. 10th, 2014 10:56 am(fixed)
Turned out, have tons of it everywhere. Weird actually.
And no, I'm not saying it's good. I'm just seeing a pattern that worries me a little bit, but I don't know why.
E.g.
type Outcome = Result[Any]
val OK:Outcome = Good("OK")
Turned out, have tons of it everywhere. Weird actually.
And no, I'm not saying it's good. I'm just seeing a pattern that worries me a little bit, but I don't know why.
E.g.
def executeJS(js: String): Result[Unit] = runJS(js) map asScala filter
("OK"==, wrong => s"Wrong response from browser: <<$wrong>>")
the right stuff
Mar. 7th, 2014 10:58 ampresentation: http://2013.flatmap.no/blakstad.html
unfiltered library: https://github.com/unfiltered/unfiltered/blob/master/directives/README.markdown
So, the idea is, have all this http run monadic; that includes checking conditions and throwing back all those 404s, 451, 500...
unfiltered library: https://github.com/unfiltered/unfiltered/blob/master/directives/README.markdown
So, the idea is, have all this http run monadic; that includes checking conditions and throwing back all those 404s, 451, 500...
good stuff from nescala
Mar. 4th, 2014 06:32 pmhttps://github.com/unfiltered/unfiltered
In short, these two Norwegians found a readable and monadic way to write http stuff.
Check out how they convert booleans to rich booleans with explanations what went wrong, and use them in monadic context.
In short, these two Norwegians found a readable and monadic way to write http stuff.
Check out how they convert booleans to rich booleans with explanations what went wrong, and use them in monadic context.
тут репост, но неважно
Что интересно - выдумают (а точнее, откроют для себя, после ознакомления с HoTT или элементами теории категорий) какую-нибудь хрень в Хаскеле, тут же где-нибудь в Скале или в С# подхватят; потом Бьярне, который не знает, почему функциональное программирование провалилось и не оправдало надежд, прочитает, ну или ему прочитают, и вот в С++ уже появляется новая революционная фича - хотя, казалось бы, С++ был уже само совершенство до того, и вся эта функциональщина ваша не приносит никакой пользы и только ухудшает эффективность.
До тех пор, пока Бьярне не скажет, что вот эта именно фича, это своевременно и давно пора. Конечно, настанет момент, когда они и от первичности материи откажутся, но он ещё за горами.
И все счастливы; и всем даже кажется почему-то, что С++, будучи совершенством, стал ещё бoльшим совершенством, и развиваться дальше некуда, но нет предела совершенствованию.
Тут можно было бы привлечь индукцию Нётер и её связь с аксиомой фундирования (я на днях обнаружил, что эту связь я когда-то давно переоткрыл, типа лет через 50 лет Эмми - и думал, о, как здорово!).
Что интересно - выдумают (а точнее, откроют для себя, после ознакомления с HoTT или элементами теории категорий) какую-нибудь хрень в Хаскеле, тут же где-нибудь в Скале или в С# подхватят; потом Бьярне, который не знает, почему функциональное программирование провалилось и не оправдало надежд, прочитает, ну или ему прочитают, и вот в С++ уже появляется новая революционная фича - хотя, казалось бы, С++ был уже само совершенство до того, и вся эта функциональщина ваша не приносит никакой пользы и только ухудшает эффективность.
До тех пор, пока Бьярне не скажет, что вот эта именно фича, это своевременно и давно пора. Конечно, настанет момент, когда они и от первичности материи откажутся, но он ещё за горами.
И все счастливы; и всем даже кажется почему-то, что С++, будучи совершенством, стал ещё бoльшим совершенством, и развиваться дальше некуда, но нет предела совершенствованию.
Тут можно было бы привлечь индукцию Нётер и её связь с аксиомой фундирования (я на днях обнаружил, что эту связь я когда-то давно переоткрыл, типа лет через 50 лет Эмми - и думал, о, как здорово!).
"patterns in scala"
Oct. 23rd, 2013 08:48 amBy the way, Pavel Fatin covered all this in his talk
http://pavelfatin.com/design-patterns-in-scala/#!
What do you think about all this? (Mine is formed by
kouzdra)
http://pavelfatin.com/design-patterns-in-scala/#!
What do you think about all this? (Mine is formed by
The stuff I write... still in doubt, is it unreadable (by the generic people)?
Too much? Too little? Primitive? Unreadable?
(take 2, более читабельно?)
type Point2d = (Double, Double)
case class Segment(topLeft: Point2d , text: String)
def buildSegment(style: String, text: String): Result[Segment] = {
// a typical style looks like this:
//style="font-size: 10.72px; font-family: serif; left: 27.84px; top: 140.96px; transform: rotate(0deg) scale(1.15535, 1); transform-origin: 0% 0% 0px;"
// we convert it to pairs like ("left", "27.84px")
val styleKeyValuePairs: Array[List[String]] = style split ";" map (_ split ":" toList)
val styleMap:Map[String, String] = styleKeyValuePairs collect { case key::value::Nil => key.trim->value.trim } toMap
def property(key: String): Result[String] = Result(styleMap get key, s"$key missing in $styleMap")
val PX = "(\\d*\\.?\\d*)px".r
def doubleValueOf(key: String): Result[Double] = property(key) collect(
{case PX(x) if !x.isEmpty => x.toDouble},
"Could not extract double from " + _
)
doubleValueOf("top") <*> doubleValueOf("left") map (Segment(_, text))
}
Too much? Too little? Primitive? Unreadable?
(take 2, более читабельно?)
Here's a little song I wrote
Oct. 20th, 2013 05:36 pmExtracting PDF from Mozilla Browser - and Doing it Nicely
That's a detailed account of the thing I already posted a couple of days ago. And what I'm enjoying here is Functional Programming. I don't know why Stroustrup does not know that it works. Worked for me. :p
That's a detailed account of the thing I already posted a couple of days ago. And what I'm enjoying here is Functional Programming. I don't know why Stroustrup does not know that it works. Worked for me. :p
applicatives in production
Oct. 17th, 2013 04:42 pm
def downloadPDF(url: String): Result[(File, String)] = {
loadPage(url) andThen
waitForSelector("div.textLayer") andThen
runJS("return extractPdfContent()") andThen {
Thread.sleep(1000) // give browser a chance
val extracted = runJS("return intBuf2hex(extractedPdf)") map (_.toString)
val pdf = extracted flatMap
(_.decodeHex #> File.createTempFile("download", ".pdf"))
val html = runJS("return _$('div.textLayer').innerHTML") map (_.toString)
pdf <*> html
}
}What happens here.
I load a page in Mozilla, via Selenium. Actually a pdf, but Mozilla pretends it's html.
andThen... (meaning, if it failed, no need to proceed, right?)Then I extract
innerHTML of the content div, I need to parse it.Oh, the
_.js means we convert the value of this string into a Javascript representation of the string, with apos escaped, wrapped in apos.But what the server sent is actually a pdf (rendered in Mozilla by pdf.js);
So I need the pdf binary. It was https, and there's no api for interception.
So I go into the guts of pdf.js, find the holder of the binary, and tell it to give me the bytes (in a continuation). But the whole communication with the browser is imperative; so I sleep for a second. No biggie.
When I wake up, the bytes I need are already pulled from pdf.js future and converted to a hex string (like 160k of text, one line).
I extract it from the browser.
Then I decode the hexes, producing bytes, and send them to a temp file; the
#> op returns the file... actually, monadically, a hope for a file. There's
flatMap here; we flatten all hopes within hopes into one big hope - or an explanation of why everything fell apart.Now we have, hopefully, a text, and, hopefully, a pdf. We apply tensor product to produce either a long list of explanations why we failed, or a tuple, a pair (text, file).
QED.
Questions? Obvious?
val listMaybe: Result[List[X]] = ...
val extractionResults: Result[List[Result[Y]]] = listMaybe map process
extractionResults map traverse flatten
I have a result of type
Result[List[Result[Y]]]; now I traverse the internal list (if it exists), obtaining Result[Result[List[Y]]], then I have to flatten it to get Result[List[Y]].Either I'm doing something non-kosher, or I need a word for this "map traverse flatten" thingie.
an impediment
Oct. 8th, 2013 06:34 pmWhat prevents me from using applicative functors that return, after tensor product, a container of a tuple, is that, before calling some Constructor.tupled, I have to carefully work on the tuple.
E.g.
would be cool, but if User constructor takes first name and last name, and DOB should be converted from String to Date...
In short, I've almost convinced myself to write additional constructors.
But then another impediment. What if I need to check the values and complain if they are wrong. Like, no Sue can be less than 70 years old, right? Something like that. And no 70-year-old can be called Tasha or Brenda or Luanda, right? In short, constructors should be partial functions, then they can be lifted.
Or...?
E.g.
getName <*> getDOB <*> getMemberID <*> flatMap (User.apply _).tupled
would be cool, but if User constructor takes first name and last name, and DOB should be converted from String to Date...
In short, I've almost convinced myself to write additional constructors.
But then another impediment. What if I need to check the values and complain if they are wrong. Like, no Sue can be less than 70 years old, right? Something like that. And no 70-year-old can be called Tasha or Brenda or Luanda, right? In short, constructors should be partial functions, then they can be lifted.
Or...?
вот так вот пишу нынче
Oct. 8th, 2013 01:44 pm
def retrieveAllPatients(listOfProps: Seq[Props]): Result[Traversable[PatientInfo]] = {
val listOfMaybePatients = listOfProps.zipWithIndex map (retrievePatientInfo _).tupled
val maybeListOfPatients = Result.traverse(listOfMaybePatients)
suspiciousError(s"Now we have all the patients, right?\n$maybeListOfPatients")
maybeListOfPatients
}
Шутки шутками, а Патерсон и МакБрайд как бы тут непосредственно вписываются.
Научите меня HoTT, и я у меня в коде будут торсоры и группы когомологий.
Смешно, конечно.