Knitting is an acceptable Lisp

So, I'm a knitter. And I pretend to be a designer some days, when I'm not knitting endless swathes of k2, p2 rib. But first and foremost, I'm an unabashed geek.

As such, I took a look at KnitML. And it's neat. Well, in theory, it's neat. In practice, I haven't got the java dependencies set up on my computer yet to play with it. I do intend to do that, and am downloading them, but while I wait for them, I want to ponder through an idea that's been percolating in my brain.

Namely, I think of knitting patterns in two ways. One is the chart. This is how I write patterns, really. And given the choice between a chart and a list of stitches, I'll pick the chart every time.

It's a question of information density. The chart presents all the information that I need, in the least amount of space while still being human-readable.

So, let's look at a chart.

It's a fairly simple pattern, embedded moss stitch rib. And can be easily transformed into a written pattern:

  1. p2, k2, p1, k1, repeat to end of round
  2. p2, k2, p1, k1, repeat to end of round
  3. p2, k1, p1, k2, repeat to end of round
  4. p2, k1, p1, k2, repeat to end of round

This is where my brain starts making clicky noises. See, my immediate reaction to that is that it's a simple program. One that generates a handsome little ribbing.

However, my second line of thought runs straight for a programming principle: Don't Repeat Yourself. My process for generating a pattern is to draw charts in Inkscape, test those charts by knitting them, then translate the chart into written instructions. In future, I may also want to make my charts available in KnitML.

What this immediately says to me as a programmer is that I should have a single piece of data from which I can generate:

  • PNG graphics
    This is the format I use to show charts. It's a useful format in that it does a good job of reducing low-colour line drawings (like knitting charts) to a fairly small file size with no loss of detail or crispness.
    This is an even worse format to use as a data source, though. Rather than just interpreting the XML that SVG gives, I'd have to start into OCR territory.
  • SVG graphics
    This is the format that I actually use to make charts. Unfortunately, it would be a considerable effort to use it as a starting point: Anything more complicated than a knit or purl stitch are relatively complex "groups", rather than simple objects.
    However, they work admirably as a way to draw charts, and from my perusal of the spec, should be able to be drawn programmatically fairly easily.
  • HTML lists
    This actually isn't a bad starting point. Not good enough that I'd want to use it as a data source, but not bad enough, either, to discard it out of hand.
    Specifically, if I look at the HTML describing the pattern:
    <ol>
      <li> p2, k2, p1, k1, repeat to end of round
      <li> p2, k2, p1, k1, repeat to end of round
      <li> p2, k1, p1, k2, repeat to end of round
      <li> p2, k1, p1, k2, repeat to end of round
    </ol>
    Other than the <ol> and <li> tags, this actually isn't a bad representation of the data at all.
  • Plaintext
    What if I were to use the plaintext representation of the aforementioned list:
    p2, k2, p1, k1, repeat to end of round
    p2, k2, p1, k1, repeat to end of round
    p2, k1, p1, k2, repeat to end of round
    p2, k1, p1, k2, repeat to end of round
    That's actually, as I alluded before, a programmatic representation of knitting. And, were it not for that pesky "repeat to end of round", would be nearly perfect.
    In fact, this is relatively close to what KnitML uses as a human-readable format, according to my reading of the spec.
  • S-Expressions
    These little gems are the core of Lisp, and are easily transformable to and from XML if the need arises.
    The core elements to them are lists and atoms. A list is multiple atoms surrounded by parentheses and separated by spaces. An atom is some text representing something.
    Thus, the pattern described above becomes:
    (repeat 2
      (repeat-to-end (p2 k2 p1 k1)))
    (repeat 2
      (repeat-to-end (p2 k1 p1 k2)))
    And any Lisp programmer reading this just started twitching. As that's not properly-formed Lisp. On the other hand, it does represent a very interesting way to mix data and instructions.
    Patterns become lists of stitches and transformative operations performed on those stitches. It's knitting as a pseudo-mathematical notation.

So, taking s-expressions as a base, what does it all mean?

Well, in that list of representations, the further along I went, the more the representation changed from being a depiction of the data to a representation. By the time we reach the plaintext version of the pattern, it is recognisable as a rudimentary program.

The s-expression version isn't even a rudimentary one; if it were fed into an interpreter that recognised the words and symbols used, it is a program to generate a knitting pattern.

Now that offers some interesting prospects, because the output of the interpreter by no means has to be fixed. For instance, I could have one interpreter that reads the pattern as a way to generate a plain text file, another interpreter that generates an SVG graphic and a third that reads the pattern as a way to generate the equivalent KnitML file.

Why does all this matter? Well, I've become interested, in the past weeks, in the idea of an editor where I type in a row of stitches and it appears on the screen as a graphical pattern. Thinking about how to represent stitches is a first step on the road to knitting pattern zen.

Shadow Check Socks - Pattern

Shadow Check Socks - Completed

Well, they took two weeks to get together, but I'm happy to say that these socks are finally a pair. Happily, they are indeed as thick, dense and warm as I'd hoped when I first started planning for them.

Requirements

  • 300m sport weight yarn
  • 3.5mm double-pointed needles
  • 3.5mm straight needles
  • A crochet hook

Measurements

  • The circumference of the ball of the foot.
  • The length of the foot.
  • The circumference of the ankle.
  • The circumference of the middle calf.
  • Your gauge in circular heel stitch.
  • Your gauge in seed rib.

For the gauges, fear not. You'll be knitting a number (quite a number, in fact) of rounds of those stitches before you need to know gauge, so it's simple to measure directly on the sock itself.

Instructions

Casting On

Perform a provisional cast on of eight stitches, knitting four rows, as for the Simple Toe-Up Socks

Heel Stitch Toe

Stitches between {braces} are repeated the number of times indicated. Stitch counts are in brackets and indicate the number of stitches on both the top and the bottom.

Knit this pattern until you have enough stitches around to go snugly around the ball of the foot. End on an even-numbered round.

  1. Knit the entire round.
  2. Top: k1, kfb, k4, kfb, k1 (10)
    Bottom: k1, kfb, k4, kfb, k1
  3. Top: k2, {s1 wyib, k1}(3 times), k2
    Bottom: k2, {k1, s1 wyib}(3 times), k2
  4. Top: k8, kfb, k1 (11)
    Bottom: k1, kfb, k8
  5. Top: k2, {s1 wyib, k1}(4 times), k1
    Bottom: k1, {k1, s1 wyib}(4 times), k2
  6. Top: k1, kfb, k7, kfb, k1 (13)
    Bottom: k1, kfb, k7, kfb, k1
  7. Top: k3, {s1 wyib, k1}(4 times), k2
    Bottom: k2, {k1, s1 wyib}(4 times), k3
  8. Top: k11, kfb, k1 (14)
    Bottom: k1, kfb, k11
  9. Top: k3, {s1 wyib, k1}(5 times), k1
    Bottom: k1, {k1, s1 wyib}(5 times), k3
  10. Top: k1, kfb, k10, kfb, k1 (16)
    Bottom: k1, kfb, k10, kfb, k1
  11. Top: k2, {s1 wyib, k1}(6 times), k2
    Bottom: k2, {k1, s1 wyib}(6 times), k2
  12. Top: k14, kfb, k1 (17)
    Bottom: k1, kfb, k14
  13. Top: k2, {s1 wyib, k1}(7 times), k1
    Bottom: k1, {k1, s1 wyib}(7 times), k2
  14. Top: k1, kfb, k13, kfb, k1 (19)
    Bottom: k1, kfb, k13, kfb, k1
  15. Top: k3, {s1 wyib, k1}(7 times), k2
    Bottom: k2, {k1, s1 wyib}(7 times), k3
  16. Top: k17, kfb, k1 (20)
    Bottom: k1, kfb, k17
  17. Top: k3, {s1 wyib, k1}(8 times), k1
    Bottom: k1, {k1, s1 wyib}(8 times), k3
  18. Top: k1, kfb, k16, kfb, k1 (22)
    Bottom: k1, kfb, k16, kfb, k1
  19. Top: k2, {s1 wyib, k1}(9 times), k2
    Bottom: k2, {k1, s1 wyib}(9 times), k2
  20. Top: k20, kfb, k1 (23)
    Bottom: k1, kfb, k20
  21. Top: k2, {s1 wyib, k1}(10 times), k1
    Bottom: k1, {k1, s1 wyib}(10 times), k2
  22. Top: k1, kfb, k19, kfb, k1 (25)
    Bottom: k1, kfb, k19, kfb, k1
  23. Top: k2, {s1 wyib, k1}(10 times), k2
    Bottom: k2, {k1, s1 wyib}(10 times), k2
  24. Top: k23, kfb, k1 (26)
    Bottom: k1, kfb, k23
  25. Top: k11, kfb, k1 (14)
    Bottom: k1, kfb, k11
  26. Top: k3, {s1 wyib, k1}(5 times), k1
    Bottom: k1, {k1, s1 wyib}(5 times), k3
  27. Top: k1, kfb, k10, kfb, k1 (16)
    Bottom: k1, kfb, k10, kfb, k1
  28. Top: k2, {s1 wyib, k1}(6 times), k2
    Bottom: k2, {k1, s1 wyib}(6 times), k2
  29. Top: k14, kfb, k1 (17)
    Bottom: k1, kfb, k14
  30. Top: k2, {s1 wyib, k1}(7 times), k1
    Bottom: k1, {k1, s1 wyib}(7 times), k2
  31. Top: k1, kfb, k13, kfb, k1 (19)
    Bottom: k1, kfb, k13, kfb, k1
  32. Top: k3, {s1 wyib, k1}(7 times), k2
    Bottom: k2, {k1, s1 wyib}(7 times), k3
  33. Top: k17, kfb, k1 (20)
    Bottom: k1, kfb, k17
  34. Top: k3, {s1 wyib, k1}(8 times), k1
    Bottom: k1, {k1, s1 wyib}(8 times), k3
  35. Top: k1, kfb, k16, kfb, k1 (22)
    Bottom: k1, kfb, k16, kfb, k1
  36. Top: k2, {s1 wyib, k1}(9 times), k2
    Bottom: k2, {k1, s1 wyib}(9 times), k2
  37. Top: k20, kfb, k1 (23)
    Bottom: k1, kfb, k20
  38. Top: k2, {s1 wyib, k1}(10 times), k1
    Bottom: k1, {k1, s1 wyib}(10 times), k2
  39. Top: k1, kfb, k19, kfb, k1 (25)
    Bottom: k1, kfb, k19, kfb, k1
  40. Top: k2, {s1 wyib, k1}(10 times), k2
    Bottom: k2, {k1, s1 wyib}(10 times), k2
  41. Top: k23, kfb, k1 (26)
    Bottom: k1, kfb, k23

Knitting the body of the sock

First, you'll need to divide the stitches again, this time onto three needles.

Count the stitches on needles 3 and 4 and divide it by three, rounding down. This is the number of stitches that should be moved from the sole to the sides and top of the sock. For the rest of the pattern, these will be referred to as “side stitches”.

For example, I have 25 stitches on needles 3 and 4 combined:

25 / 3 = 8 1/3

8 1/3 ≈ 8

So I want to move eight stitches, or four from each side. First, transfer all the stitches from needle 4 to needle 3. Needle 3 will knit the sole of the sock, needles 1 and 2 will knit the top. Next, place a marker at the end of needle 1 and transfer half of the side stitches from needle 3 to needle 1. Place a marker at the end of needle 2 and transfer the other half of the stitches from needle 3 to needle 2. If you are moving an odd number of stitches, move the extra stitch to the needle that has fewer toe increases (needle 1 for a right sock, needle 2 for a left.)

Count the stitches on needle 3 again. If there is an odd number of stitches, perfect. If, on the other hand, it's even, transfer one more stitch. If you transferred an odd number before, place this extra stitch on the opposite needle from the odd stitch. Otherwise, place it on the needle with fewer toe increases, as above.

The pattern for the body of the sock is 6 rounds long. Stitches in {braces} are repeated, either to the end of needle 3 (for bottom stitches) or until the end of needle 2 (for top). The side stitches are knit in pattern for the top.

  1. Top: {Knit 1}
    Bottom: {Purl 1}
  2. Top: {k1, p1}
    Bottom: p1, {k1, p1}
  3. Top: {p1}
    Bottom: p1, {yop, s1 wyib, purl 1} Here, the yarn should wrap over the slipped stitch, making one stitch crossed over the other.
  4. Top: {k1}
    Bottom: p1, {drop the yo from the previous row, si wyib, p1} Dropping the yarn over looks like it should leave a very loose stitch around the slipped stitch. However, purling the next stitch adjusts its tension, bringing it tighter once more.
  5. Top: {p1, k1}
    Bottom: p1, {s1 wyib, p1}
  6. Top: {p1}
    Bottom: p1, {s1 wyib, p1}

Knitting a gusseted heel

This is a slight adaptation of the heel described in the Simple Toe-Up Socks pattern.

Continue knitting the 6 rounds of pattern for the body until it measures 70% of the length of the foot. For me, each pattern repeat is less than a centimetre long, so you can expect this to be rather a lot of knitting. My foot is 22cm long, so I calculate that as follows:

22 cm ∗ 0.7 = 15.39 cm

Finish on round 6 of the body pattern, having just knit the bottom of the sock.

For the next while, needles 1 and 2 will not be used, so do what you will with the stitches on them, be it transferring them to a holder, placing them on a spare needle or scrap of yarn or simply leaving them on the two double-pointed needles.

The heel is knit flat and the yarn is currently placed so that the next row is the wrong side, so, to complete the shadow check pattern, knit the row, which will finish the sole with a row of purl stitches. Then, with straight needles of the same size as your double-pointed needles, knit the following 2-row pattern:

Heel Stitch
  1. (right side) k1, {s1, k1}
  2. Purl the row

This is heel stitch again. However, since there are no increases or decreases at play, it's 16 times simpler than it was at the toe.

Knit this until the heel is 95% of the length of the foot (i.e. 4-6 rows below the foot length).

Turning the heel

Next, knit row 1 of the heel stitch pattern, stopping 2 stitches before the end of the row. Turn the sock and knit row 2, stopping 2 stitches before the end of the row.

Knit row 1 again, stopping 4 stitches before the end of the row, then row 2, stopping 4 stitches before the end of the row.

Continue like this, losing two more stitches each row, until you have either 9 or 7 stitches left live and have just completed a purl row (row 2).

Next, knit row 1 again, knitting the last live stitch together with the first saved stitch and knitting the second saved stitch. Turn your work and knit row 2, purling the last live stitch together with the first saved stitch and purling the second saved stitch.

Repeat those two steps until all the stitches are live again. Congratulations. You're halfway done the heel.

Picking up from the heel flap

You should have just completed a purl row so, to get your yarn in position to knit in the round, knit across the heel one more time, this time using two double-pointed needles, one holding each half of the heel.

Begin picking up stitches along the side of the heel flap with the second double-pointed needle used to knit the heel. If you look at the selvedge, you should have a raised row of slipped stitches below a slightly-curled row of knit stitches. You'll want to pick up one stitch per row along the heel, so insert a needle in the hole beneath the two strands of the knit stitch, insert your double-pointed needle into the hole underneath it and knit one stitch.

Repeat this for every row of the heel, as well as picking up two stitches from the first stitch on the top of the sock in order to ensure that there's not a hole between the heel and the top of the sock. Note the number of stitches you picked up, place a marker at the end of the needle and knit the side stitches onto it. This keeps you from working the decreases across a gap between needles.

Knit across the top of the sock, transferring stitches onto two double-pointed needles if needs be. With the second double-pointed needle, pick up the same number of stitches along the heel flap as you did on the other side, leaving a marker before the picked-up stitches.

Finally, transfer the picked-up stitches and the side stitches to the other needle on the back of the sock. Time for the final change in needle numbering. As before, the needles are numbered in clockwise order. The two across the top of the foot are needles 2 and 3. The two making up the heel are 1 and 4.

That's it. The heel has been turned, the stitches have been picked up. All that's left is to decrease the heel gusset until the sock is the same size as it was at the ball of the foot.

Gusseting

Compared to everything you've been through so far, this bit is easy. Knit each round using the seed rib pattern. To determine where in the pattern to start count the number of stitches on needle 1. If it's even, start the pattern on round 1, if it's odd, start on round 4.

Two stitches before the marker on needle 1, stop. If you are on a knit round, K2TOG. If you are on a purl round, P2TOG. If you are on a seed round, do not decrease.

Continue knitting seed rib until you get to the marker on needle 4. If you are on a knit round, SSK. If you are on a purl round, S1, P1, PSSO. If you are on a seed round, do not decrease.

Continue knitting this pattern until you have the same number of stitches as you did for the ball of the foot.

Seed Rib
  1. Knit the round
  2. k1, p1, repeat
  3. Purl the round
  4. Knit the round
  5. p1, k1, repeat
  6. Purl the round

The half above the black line is the normal pattern repeat. The part below is the general pattern for the gusset decreases.

Ankle

If the ankle is to be smaller than the ball of the foot, continue knitting seed rib for three rounds. Once you have done that, work decreases as follows:

If you are on a seed round, do not decrease.

If you are on a knit round, knit the first stitch of needle 1, SSK, knit to the last three stitches on needle 4, K2TOG, K1.

If you are on a purl round, purl one stitch, S1, P1, PSSO, purl to the last three stitches on needle 4, P2TOG, P1.

Decrease in this way until you have the right number of stitches for the ankle.

Calf

Knit four repeats of the seed rib pattern. Count your stitches. If they are not divisible by 6, increase via KFBs in the knit rounds as you knit rounds 1-5 of a fifth repeat. Otherwise, knit those rounds without increase.

That done, it's time to begin ribbing. The pattern for the rib is another Barbara Walker one: embedded moss stitch ribbing, with a single amendment. It'll be worked over 6 stitches, rather than 7, to ensure that its repeat length matches that of the seed rib.

Embedded Moss Stitch Ribbing

Repeat these 6 stitches around the entire circumference of the sock.

  1. p2, k2, p1, k1
  2. p2, k2, p1, k1
  3. p2, k1, p1, k2
  4. p2, k1, p2, k2

This gives a rib that is a 2-stitch purl gutter between columns of knit stitches, with a twocolumn moss stitch pattern between them.

Knit this ribbing until the sock is as long as you want it, knit two rounds in P2, K4 ribbing, then cast off very loosely with the following pattern: P2, K4.