In slick, if each foo has many bars and I need to retrive several foos and associtated bars I will do something like this:
val join = for {
(f,b) <-
foo.filter(...) on innerJoin
bar on (...)
} yield (o,i,s)
The type of join will be a List[(foo,bar)]. I want the bars grouped by foo, not a tuple of each. I can transform to a grouped format like so:
def group1[A,B](t : List[(A,B)]) : List[(A,List[B])] = {
val map = LinkedHashMap[A, LinkedHashSet[B]]()
for (i <- t) {
val key = i._1
map(key) = map.lift(key).getOrElse(LinkedHashSet[B]()) + i._2
}
map.map(b => (b._1,b._2.toList)).toList
}
This groups one element from a tuple into a sublist. If I later add the requirement that each bar has many baz than I need to another method that transforms tuples of 3 into two nested lists.
def group2[A,B,C](t : List[(A,B,C)]) : List[(A,List[(B,List[C])])] = {
group2Internal(t).map(x => (x._1,group1(x._2)))
}
private def group2Internal[A,B,C](t : List[(A,B,C)]) : List[(A,List[(B,C)])] = {
val map = LinkedHashMap[A, LinkedHashSet[(B,C)]]()
for (i <- t) {
val key = i._1
map(key) = map.lift(key).getOrElse(LinkedHashSet[(B,C)]()) + ((i._2,i._3))
}
map.map(b => (b._1,b._2.toList)).toList
}
I can do the same for grouping into three nested lists:
def group3[A,B,C,D](t : List[(A,B,C,D)]) : List[(A,List[(B,List[(C,List[D])])])] = {
group3Internal(t).map(x => (x._1,group2(x._2)))
}
private def group3Internal[A,B,C,D](t : List[(A,B,C,D)]) : List[(A,List[(B,C,D)])] = {
val map = LinkedHashMap[A, LinkedHashSet[(B,C,D)]]()
for (i <- t) {
val key = i._1
map(key) = map.lift(key).getOrElse(LinkedHashSet[(B,C,D)]()) + ((i._2,i._3,i._4))
}
map.map(b => (b._1,b._2.toList)).toList
}
There is obviously a pattern here that should be abstractable. However, at the type level, tuples of different sizes are unqiue types, so this gets tricky. It should be possible to use the shapeless library to abstract over the tuple size. In practice I never need more than group3, so this will stay in its expanded form for now.
]]>This blog was on tumblr, which was easy to setup and post and such. However, I spend like 8 hours a day with a text editor open and a git in terminal window. Also I’m always look for an excuse to use haskell. So I’m moving things over to Hakyll. I followed this great tutorial on how to setup things up with CircleCI, so now I just commit and push and my site updates.
So far, so good.
]]>This post is a work in progress and represents my getting to understand how laziness works in haskell and how it affects performance.
Summary of Laziness:
Lazy is good when:
Strict is good otherwise.
Hence:
The key insight for me has been understanding that lazy evaluation means that functions take in a pointer to a thunk as arguments and then return a thunk as a value. Only looking inside those thunks inputs (via pattern matching or IO) actually forces anything.
This level of indirection improves composability, you can generate than reduce in a more modular fashion with only some constant overhead for holding on to thunks. The paper “why functional programming matters” has a great explanation of this.
This all works because whenever you throw something away with i.e. f (a,) = a, the pointer to the thunk, that was never evaluated, and all the evaluations that follow from can get garbage collected away.
This how foldr can short-circuit on some lazy list, if a condition of f that is passed in doesn’t care about the rest of the list, then we are done.
Links:
]]>In an old essay, Paul Graham, talks about how some languages are more succinct and therefore they are more powerful. In fact, some programming languages can say things that you can’t easily say in others. Maybe you can’t say them at all. Its a good essay overall, you should read it.
His Example:
Write a function that takes a number n, and returns a function that takes another number i and returns n incremented by i.
I think this example is, maybe, unfairly biased towards functional programming languages, and its no surprise that pg shows us that lisp has the shortest implementation.
It works as a good example, however, because it shows us a concrete demonstration where one language can easily do something (lisp), that others languages are not able to do at all (java).
Let me try this in haskell.
So in Haskell, the type of this function f would be:
f :: Num a => a -> ( a -> a)
meaning f takes a number and returns a function that takes a number and returns another number.
Since the brackets are right associative, we can drop them to get:
f :: Num a => a -> a -> a
This is because, in haskell, all functions are considered curried and can be partially applied. Even basic numerical functions like + - / if given one argument will return a function that excepts the next argument.
For example:
:t (+)
(+) :: Num a => a -> a -> a
:t (+) 4
(+) 4 :: Num a => a -> a
So (+) 4 returns a function that takes a number and then adds 4 for to it. (I mean, I guess technically, it doesn’t add 4 to it, but returns a new number that is the sum of them, but I think I am still capturing the spirit of the exercise here. Haskell variables are not mutable.)
What all of this means, if I haven’t already telegraphed the punchline, is that the complete haskell solution is:
f = (+)
So, in haskell, we don’t need to write this function. We can just use +.
I think that is pretty cool.
]]>How to get bluetooth working in windows 8 / 8.1 on various thinkpads.
Currently, the thinkpads ( w520 for sure, but lots of complaints about others online) do not have working bluetooth drivers. Or rather the driver exists, but getting the bluetooth to turn on is not possible.
I have put together a solution here:
https://dl.dropboxusercontent.com/u/7773580/lenovo/Adams%20bt%20enable.zip
This zip has to batch files that will turn on or off the blue tooth device. It uses the hotkey exe from the windows 7 Lenove hotkey app to force the bluetooth on.
It also contains a bluetooth driver, the one I originally used, however I recommend instead that you go straight to broadcom here:
]]>I got my new teck keyboard from massdrop. It takes some getting used to, but I’m already typing faster. Check out the autohotkey script I used to ease the transition.
In my effort to become a better touch typer, I began looking into ergnomic and mechanical keyboards. The cream of the crop for ergonomic symetric mechanical keyboards appears to be the ergodox. It is open source hardware, so you basically have to order the parts your self and get out your soldering gun. They sell these in kit form all the time on massdrop, but this seemed like a little more effort than I wanted to put into a keyboard at this juncture, so when massdrop did a mass buy for the so call Truly Ergonomic Keyboard, which is a compromise between a traditional keyboard and ergodox, I jumped on it and got my TECK as 25% off.
Keyboard arrived very quickly from massdrop and I’ve been using it full time for about a month now. I made some modifications to the keymapping using the the included software, switching the control and shift keys to more traditional spots. I also used AutoHotkey on windows and xcape on Ubuntu to get my right control to work as an enter key if pressed alone and some other similar tweaks.
but i want to be backward compatible with traditional keyboards so switched it back
I want to be able to use normal keyboards when I have to, so I made some tweaks to the TECK keyboard to keep it close to default layout.
switched key caps - CTRL and SHIFT
right control is enter if pressed alone
left control is ESC alone (vimness) means my control is like my old caps lock
tried mapping shift on its own to tab, but messed up my shift tabbing
References:
]]>Problem:
I want to use emacs like I use notepadd++ on windows.
That is:
Here are the steps I took:
Create the context menu like this (global_context_emacs.reg) :
REGEDIT4
[HKEY_CLASSES_ROOT\*\shell]
[HKEY_CLASSES_ROOT\*\shell\openwemacs]
@="&GNU Emacs"
# The above value appears in the global context menu, # i.e., when you right click on a file.
# (The '&' makes the next character a shortcut.) "Icon"="C:\\Program Files\\Emacs\\bin\\emacs.exe,0"
# The above uses the icon of the Emacs exe for the context # and should match the path used for the command below.
# The ,0 selects the main icon. [HKEY_CLASSES_ROOT\*\shell\openwemacs\command]
@="C:\\Program Files\\Emacs\\bin\\runemacs.exe \"%1\""
# The above has to point to where you install Emacs
Create a batch file called runclientw.bat and compile to exe and associate file types as needed. See here
How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?
By Hand:
There are 12 * 100 first of the months, 1/7 of them fall on sundays, therefore euler19 = 1200/7 ~= 171
In haskell:
euler19 = length $ filter isSunday [(year,month) | year <- [1901..2000], month <- [1..12]] isSunday :: (Integer,Int) -> Bool isSunday (year, month) = isSunday1 $ toWeekDate $ fromGregorian year month 01 where isSunday1 (_,_,7) = True isSunday1 _ = False
“Functor is to Lens as Applicative is to Biplate”
Haskell, the language with seemingly endless new concepts to learn about
]]>What is the greatest product of four adjacent numbers in any direction (up, down, left, right, or diagonally) in the 2020 grid?
It took me forever to find out that transpose existed and that I could use zipWith to get a diagonal - but after that its gets easy.
euler11 = maximum( (maxGridProduct q10Grid) --max of row products :(maxGridProduct $ transpose q10Grid) --max of column products :(maxGridProduct $ diagonalGrid q10Grid) --max of first diagonal :(maxGridProduct $ diagonalGrid $map reverse q10Grid) --max of second diagonal :(maxGridProduct $ diagonalGrid $ transpose q10Grid) --max of first transposed :(maxGridProduct $ diagonalGrid $map reverse $ transpose q10Grid)--max of second : [] ) maxGridProduct :: [[Int]] -> Int maxGridProduct grid = maximum $ map maxRowProduct grid maxRowProduct :: [Int] -> Int maxRowProduct line = maximum . map (product . take 4) $ tails $ line diagonalGrid grid = map (diagonalRow grid) [0..(length grid)] diagonalRow :: [[Int]] -> Int -> [Int] diagonalRow grid offset = zipWith (!!) grid [offset .. max] where len = length $ grid!!0 max = len - 1 q10Grid ::[[Int]] q10Grid = map (map read) $ stringNum where stringNum = map words $ lines " \ \08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08\n \ \49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00\n \ \81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65\n \ \52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91\n \ \22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80\n \ \24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50\n \ \32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70\n \ \67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21\n \ \24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72\n \ \21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95\n \ \78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92\n \ \16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57\n \ \86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58\n \ \19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40\n \ \04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66\n \ \88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69\n \ \04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36\n \ \20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16\n \ \20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54\n \ \01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48"]]>