ma

The Armies march to Partizan

The last Dwarf base done just in time for the big weekend. It's the Other Partizan show this weekend and I'll be there with my armies. So if you fancy seeing a massive Hobbit battle...pop along.

The battle will be fought using the new Midguard rules by James Morris. It proves to be a great Sunday especially if you're a Tolkien fan.

Today I have collect everything together and pack it as best I can to stop any travel casualties. I have always painted my figures to play at home so have never magnetised them onto metal sheets.

 I'm going to rely on nonslip matting and bubble wrap to get them there...I'm planned for a few accidents by hopefully, touch wood, all will be okay. It's been a lot of last minute painting but I'm looking forward to it.

Most of these Dwarves are old sculpts from Nick Lund.
That Reaper figure jumped the painting que and made the last company to leave the Iron Hills.

A couple of last minute Bolg bodyguard bases. I had planned to do more but time caught up with me. At least all the important stuff is done, like Beorn and the Eagles.
A coat of gloss on weapon edges and armour helps to catch the eye on the metal work. Dwarves are master smiths after all, their armour and weapons would be of high quality.

 Come along on Sunday it would be nice to see you.



Finally the two meet, Bolg and bigger Beorn.
My old Beorn figure is dwarfed by the new addition. The new bear has a lot more presence to him and should look the part on Sunday.



  • lord Of The Rings
  • lord Of The Rings.

ma

Halfords Mat Lacquer

I thought I'd give this a go as I had heard good things about it. I thought the scenic rock pools would be the perfect test subject, as if they dried glossy it wouldn't matter.
The results were good. I sprayed the models after I had added some flock, I thought the lacquer would help seal it.
After the scenic pieces I thought I'd try it on the new Irish figures. I consider this a tough, hard coat. Another layer of super mat varnish will be added with a brush when this first coat is dry.
The rock pools got a layer of flock really nail the realistic look.

 The flock and paint work is all sprayed with the new lacquer, seems to be a winner.




ma

Joe Marshall: Lisp vs. golang

It's no secret that I'm an aficionado of Lisp. It's my go to language, especially when I don't know what I'm doing. I call it research and prototyping, but it's really just playing around until something works.

We had a need for some auditing of some of our databases at work. They ought to agree with each other and with what GitHub and CircleCI think. It took a couple of weeks part time to prototype a solution in Common Lisp. It showed that the databases were in 99% agreement and found the few points of disagreement and anomalies that we ought to fix or look out for.

I want to integrate this information into a dashboard on one of our tools. I prototyped this by spinning up a Common Lisp microservice that returns the information in JSON format.

But management prefers that new services are written in golang. It would be easier for me to rewrite the service in golang than to try to persuade others to use Common Lisp. It also gives me the opportunity to compare the two languages head to head on a real world problem.

No, this is not a fair comparison. When I wrote the Lisp code I was exploring the problem space and prototyping. I'm much more experienced with Lisp than with golang. The golang version has the advantage that I know what I want to do and how to do it. In theory, I can just translate the Common Lisp code into golang. But then again, this is a “second system” which is not a prototype and has slightly larger scope and fuller requirements. So this cannot be a true head to head comparison.

The first point of comparison is macros (or lack thereof). I generally don't use a lot of macros in Common Lisp, but they come in handy when I do use them. One macro I wrote is called audit-step, which you can wrap around any expresion and it prints out a message before and after the expression is evaluated. The steps are numbered in sequence, and nested steps get nested numbers (like step 2.3.1). If you wrap the major function bodies with this macro, you get a nice trace of the call sequence in the log.

Golang doesn't have macros, but it has first class functions. It's easy enough to write a function that takes a function as an argument and wraps it to output the trace messages. In fact, the macro version in Common Lisp just rewrites the form into such a function call. But the macro version hides a level of indentation and a lambda. In golang, my major functions all start with

func MajorFunction (args) int {
        return AuditStep("MajorFunction", "aux message", func() int {
                // body of MajorFunction
                // Actual code goes here.
        })    
}

The bodies of all my major functions are indented by 16 spaces, which is a little much.

I like higher order functions. I can write one higher order function and parameterize it with functions that handle the specific cases. In my auditing code, one such workhorse function is called collate. It takes a list of objects and creates a table that maps values to all objects in the list that contain that value. To give an example, imaging you have a list of objects that all have a field called foo. The foo field is a string. The collate function can return a table that maps strings to all objects that have that string in the foo field.

collate is very general. It takes a list of objects and four keyword arguments. The :key argument is a function that extracts the value to collate on. The :test argument is a function that compares two keys (it defaults to eql if not specified). The :merger argument is a function to add the mapped object to its appropriate collection in the table (it defaults to adjoin). The :default argument specifies the initial value of a collection in the table (it defaults to nil).

The :merger function is the most interesting. It takes the key and the object and the current value of the table at that key. It returns the new value of the table at that key. The default merger function is adjoin, which adds the object to the collection at the key if it is not already there. But you can specify a different merger function. For example, if you want to count the number of objects at each key, you can specify a merger function that increments a counter.

The functional arguments to the collate function are often the results of other higher order functions. For example, the :key argument is often the result of composing selector functions. The :merger argument is often the result of composing a binary merge function with a unary transformer function. The transformer function is often the result of composing a number of primitive selectors and transformers.

In Common Lisp, it is quite easy to write these higher order functions. We can compose two unary functions with the compose2 function:

(defun compose2 (f g)
  (lambda (x) (funcall f (funcall g x)))

and then compose as many functions as we like by fold-left of compose2 starting with the identity function:

(defun compose (&rest fs)
  (fold-left #'compose2 #'identity fs))

We can compose a binary function with a unary function in three ways: we can pipe the output of the binary function into the unary function, or we can pipe the output of the unary function into one or the other of the inputs of the binary function.

(defun binary-compose-output (f g)
  (lambda (x y) (funcall f (funcall g x y))))

(defun binary-compose-left (f g)
  (lambda (x y) (funcall f (funcall g x) y)))

(defun binary-compose-right (f g)
  (lambda (x y) (funcall f x (funcall g y))))

The collate function can now assume that a lot of the work is done by the :key and :merger functions that are passed in. It simply builds a hash table and fills it:

(defun collate (item &key (key #'identity) (test #'eql) (merger (merge-adjoin #'eql)) (default nil))
  (let ((table (make-hash-table :test test)))
    (dolist (item items table)
      (let ((k (funcall key item)))
        (setf (gethash k table) (funcall merger (gethash k table default) item))))))

(defun merge-adjoin (test)
  (lambda (collection item)
    (adjoin item collection :test test)))

So suppose, for example, that we have a list of records. Each record is a three element list. The third element is a struct that contains a string. We want a table mapping strings to the two element lists you get when you strip out the struct. This is easily done with collate:

(collate records
  :key (compose #'get-string #'third)
  :test #'equal      ; or #'string= if you prefer
  :merger (binary-compose-right (merge-adjoin #'equal) #'butlast))

The audit code reads lists of records from the database and from GitHub and from CircleCI and uses collate to build hash tables we can use to quickly walk and validate the data.

Translating this into golang isn't quite so easy. Golang has first class function, true, but golang is a statically typed language. This causes two problems. First, the signature of the higher order functions includes the types of the arguments and the return value. This means you cannot just slap on the lambda symbol, you have to annotate each argument and the return value. This is far more verbose. Second, higher order functions map onto parameterized (generic) types. Generic type systems come with their own little constraint language so that the computer can figure out what concrete types can correctly match the generic types. This makes higher order functions fairly unweildy.

Consider compose2. The functions f and g each have an input and output type, but the output type of g is the input type of f so only three types are involved

func Compose2[T any, U any, V any](f func(U) V, g func(T) U) func(T) V {
	return func(x T) V {
		return f(g(x))
	}
}

If want to compose three functions, we can write this:

func Compose3[T any, U any, V any, W any](f func(V) W, g func(U) V, h func(T) U) func(T) W {
	return func(x T) W {
		return f(g(h(x)))
	}
}
The generic type specifiers take up as much space as the code itself.

I don't see a way to write an n-ary compose function. It would have to be dynamically parameterized by the intermediate types of all the functions it was composing.

For the collate function, we can write this:

func Collate[R any, K comparable, V any](
	list *Cons[R],
	keyfunc func(R) K,
	merger func(V, R) V,
	defaultValue V) map[K]V {
	answer := make(map[K]V)
	for list != nil {
		key := keyfunc(list.Car)
		probe, ok := answer[key]
		if !ok {
			probe = defaultValue
		}
		answer[key] = merger(probe, list.Car)
		list = list.Cdr
	}
	return answer
}

We have three types to parameterize over: the type of the list elements (i.e. the record type) R, the type of the key K, and the type of the value V. The key type is needs to be constrained to be a valid key in a map, so we use the comparable constraint. Now that we have the types, we can annotate the arguments and return value. The list we are collating is a list of R elements. The key function takes an R and returns a K. The merger takes an existing value of type V and the record of type R and returns a new value of type V.

The magic of type inference means that I do not have to annotate all the variables in the body of the function, but the compiler cannot read my mind and infer the types of the arguments and return value. Golang forces you to think about the types of arguments and return values at every step of the way. Yes, one should be aware of what types are being passed around, but it is a burden to have to formally specify them at every step. I could write the Common Lisp code without worrying too much about types. Of couse the types would have to be consistent at runtime, but I could write the code just by considering what was connected to what. In golang, the types are in your face at every function definition. You not only have to think about what is connected to what, you have to think about what sort of thing is passed through the connection.

I'm sure that many would argue that type safety is worth the trouble of annotation. I don't want to argue that it isn't. But the type system is cumbersome, awkward, and unweildy, especially when you are trying to write higher order functions.

It is taking me longer to write the golang version of the audit service than it did to write the Common Lisp version. There are several reasons. First, I am more experienced with Common Lisp than golang, so the right Common Lisp idioms just come to mind. I have to look up many of the golang idioms. Second, the golang code is trying to do more than the Common Lisp code. But third, golang itself introduces more friction than Common Lisp. Programs have to do more than express the algorithm, they have to satisfy the type system.

There are more points of comparison between the two languages. When I get frustrated enough, I'll probably write another post.




ma

Joe Marshall: Don't Try to Program in Lisp

A comment on my previous post said,

The most difficult thing when coming to a different language is to leave the other language behind. The kind of friction experienced here is common when transliterating ideas from one language to another. Go (in this case) is telling you it just doesn't like to work like this.
Try writing simple Go, instead of reaching for Lisp idioms. Then find the ways that work for Go to express the concepts you find.

That's not at all how I approach programming.

A friend of mine once paid me a high compliment. He said, “Even your C code looks like Lisp.”

When I write code, I don't think in terms of the language I'm using, I think in terms of the problem I'm solving. I'm a mostly functional programmer, so I like to think in terms of functions and abstractions. I mostly reason about my code informally, but I draw upon the formal framework of Lambda Calculus. Lambda Calculus is a simple, but powerful (and universal) model of computation.

Programming therefore becomes a matter of expressing the solution to a problem with the syntax and idioms of the language I'm using. Lisp was inspired by Lambda Calculus, so there is little friction in expressing computations in Lisp. Lisp is extensible and customizable, so I can add new syntax and idioms as desired.

Other languages are less accommodating. Some computations are not easily expressable in the syntax of the language, or the semantics of the language are quirky and inconsistent. Essentially, every general purpose fourth generation programming language can be viewed as a poorly-specified, half-assed, incomplete, bug-ridden implementation of half of Common Lisp. The friction comes from working around the limitations of the language.




ma

Estonia 039 s National Animal

Estonia 039 s National Animal



View Comic!








ma

Why Virat Kohli, Jasprit Bumrah were missing from Perth nets; India ramp up privacy amid Manchester United-like security - Hindustan Times

  1. Why Virat Kohli, Jasprit Bumrah were missing from Perth nets; India ramp up privacy amid Manchester United-like security  Hindustan Times
  2. Virat Kohli in focus: Intense net session begins for upcoming Test series against Australia  The Times of India
  3. Virat Kohli in Australia for BGT: A timeline  India Today
  4. Black veil of secrecy: India begin training in privacy in Perth  ESPNcricinfo
  5. India to play intra-squad warm-up match at WACA on Friday ahead of Australia Tests but BCCI denies public viewing  Hindustan Times




ma

Eight injured in explosion at oil refinery in UP's Mathura - ANI News

  1. Eight injured in explosion at oil refinery in UP's Mathura  ANI News
  2. 8 injured, three critical in major explosion at Indian Oil plant in UP's Mathura  India Today
  3. Eight injured in fire at IndianOil’s Mathura refinery  BusinessLine
  4. Mathura refinery blast: Indian Oil refinery explosion injures 12 people  The Financial Express
  5. At least 8 injured in explosion at Mathura refinery  The Indian Express




ma

3 Children, 3 Women Missing After 10 Suspected Kuki Militants Killed In Encounter In Manipur's Jiribam - NDTV

  1. 3 Children, 3 Women Missing After 10 Suspected Kuki Militants Killed In Encounter In Manipur's Jiribam  NDTV
  2. Manipur on boil: 2 more bodies found, 6 missing  The Times of India
  3. Additional paramilitary forces rushed to Manipur amid spike in ethnic violence  Hindustan Times
  4. Letters to The Editor — November 13, 2024  The Hindu
  5. 2 men found dead, 6 of family missing day after militants killed in Manipur  India Today




ma

he was a good man

Today on Married To The Sea: he was a good man


This RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see!




ma

hey man like water

Today on Married To The Sea: hey man like water


This RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see!




ma

mass media cents

Today on Married To The Sea: mass media cents


This RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see!




ma

pinterest image

Today on Married To The Sea: pinterest image


This RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see!




ma

may you stay safe

Today on Married To The Sea: may you stay safe


This RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see!




ma

go forth strong man

Today on Married To The Sea: go forth strong man


This RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see!




ma

marbles magic

Today on Married To The Sea: marbles magic


This RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see!




ma

machine that makes fucks

Today on Married To The Sea: machine that makes fucks


This RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see!




ma

rich people are smarter

Today on Married To The Sea: rich people are smarter


This RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see!




ma

martin luther

Today on Married To The Sea: martin luther


This RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see!




ma

welcome to the magical lair

Today on Married To The Sea: welcome to the magical lair


This RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see!




ma

amazon porch pirates

Today on Married To The Sea: amazon porch pirates


This RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see!
















ma

At Least It Matches!

I don't know which is better: the fact that building maintenance color-coordinated the tape with the soap, or that they neglected to put the soap back in the dispenser (it's in the bag in the corner).




ma

Meet BRAD (Berkeley's Ridiculously Automated Dorm Room)

Party the absolute hardest you can imaginably party!





ma

Mad Science Monday: Never Visit The Dentist Again

I think the next logical step is a pulled-tooth via skydiving.

~NSHA




ma

How to Open a Beer the Drunken Woodsman Way!

Did you keep waiting for the moment where something was going to go horribly wrong?

Yeah, me too.




ma

McDonnell ends his Armagh career

Armagh football suffers another blow as Steven McDonnell announces his retirement from the intercounty game.




ma

Quigley stars in Fermanagh win

Fermanagh trounce Leitrim in their National Football League Division Four game at Brewster Park.




ma

Cavan name Hyland as new manager

Terry Hyland and assistant Anthony Forde take over at Cavan after the resignation of Val Andrews.




ma

Justin McMahon fit to face Armagh

Tyrone expect Justin McMahon to be fit to play in the Ulster championship opener against Armagh on June 10.




ma

Bev Priestman fired as Canada women's soccer coach after Olympic drone scandal

Canada women's soccer coach Bev Priestman has been fired after an independent review of a drone surveillance scandal at the Paris Olympics




ma

Opportunity knocks for USMNT's Ricardo Pepi: 'I'm feeling ready to be the man'

With several U.S. men's national team strikers out with injuries, 21-year-old Ricardo Pepi has a golden opportunity to prove why he deserves to be Mauricio Pochettino top choice up top.




ma

Kyler Murray, Brock Purdy move up, Caleb Williams on bottom of Mahomes Mountain | First Things First

Nick Wright reveals who climbs up and down his Week 11 QB Tiers, including Kyler Murray and Brock Purdy, who will face each other in the final game of the regular season with playoffs on the line. Watch as Nick explains why Caleb Williams is not off Mahomes Mountain yet despite a change in the Chicago Bears coaching staff.




ma

Alabama's Ryan Williams on Travis Hunter winning Biletnikoff: 'I can't let him do that'

In an interview on FOX Sports' "All Facts, No Brakes," Alabama stars Ryan Williams and Jaylen Mbakwe shared why they stayed after Nick Saban's retirement and their thoughts on Travis Hunter.




ma

Matthew Nicholson throws down a two-handed slam to help Northwestern lead over UIC going into the half

Matthew Nicholson threw down a two-handed slam to help the Northwestern Wildcats lead over the the UIC Flames going into the half.




ma

Deion Sanders compares Shedeur and Travis’ chemistry to Michael Irvin and Troy Aikman | Speak

Deion Sanders talks about the strong chemistry between Shedeur Sanders and Travis Hunter, comparing it to the connection Michael Irvin had with Troy Aikman during their playing days.




ma

Deion Sanders argues why Travis Hunter is a Heisman front-runner this year | Speak

Deion Sanders argues why Travis Hunter is a top contender for the Heisman this year, highlighting his unique talent and impact on Colorado’s success.




ma

Mavs' Klay Thompson cheered by 400 Warriors employees in return to Golden State

Klay Thompson was greeted by some 400 cheering Warriors employees showing their love and appreciation for the former Golden State star and lined up along his path to the Dallas locker room