Haskell type checker complaint 184 of 698
I want to build an adjacency matrix for the vertices of a cube; this
is a matrix that has m[a][b] = 1 exactly when vertices a and b
share an edge. We can enumerate the vertices arbitrarily but a
convenient way to do it is to assign them the numbers 0 through 7 and
then say that vertices !!a!! and !!b!! are adjacent if, regarded as
binary numerals, they differ in exactly one bit, so:
import Data.Bits
a `adj` b = if (elem (xor a b) [1, 2, 4]) then 1 else 0
This compiles and GHC infers the type
adj :: (Bits a, Num a, Num t) => a -> a -> t
Fine.
Now I want to build the adjacency matrix, which is completely
straightforward:
cube = [ [a `adj` b | b <- [0 .. 7] ] | a <- [0 .. 7] ] where
a `adj` b = if (elem (xor a b) [1, 2, 4]) then 1 else 0
Ha ha, no it isn't; in Haskell nothing is straightforward. This
produces 106 lines of type whining, followed by a failed compilation.
Apparently this is because because 0 and 7 are overloaded, and
could mean some weird values in some freakish instance of Num , and
then 0 .. 7 might generate an infinite list of 1-graded torsion
rings or something.
To fix this I have to say explicitly what I mean by 0 . “Oh, yeah,
by the way, that there zero is intended to denote the integer zero,
and not the 1-graded torsion ring with no elements.”
cube = [ [a `adj` b | b <- [0 :: Integer .. 7] ] | a <- [0 .. 7] ] where
a `adj` b = if (elem (xor a b) [1, 2, 4]) then 1 else 0
Here's another way I could accomplish this:
zero_i_really_mean_it = 0 :: Integer
cube = [ [a `adj` b | b <- [zero_i_really_mean_it .. 7] ] | a <- [0 .. 7] ] where
a `adj` b = if (elem (xor a b) [1, 2, 4]) then 1 else 0
Or how about this?
cube = [ [a `adj` b | b <- numbers_dammit [0 .. 7] ] | a <- [0 .. 7] ] where
p `adj` q = if (elem (xor p q) [1, 2, 4]) then 1 else 0
numbers_dammit = id :: [Integer] -> [Integer]
I think there must be something really wrong with the language design
here. I don't know exactly what it is, but I think someone must have
made the wrong tradeoff at some point.
[Other articles in category /prog/haskell]
permanent link
How not to reconfigure your sshd
Yesterday I wanted to reconfigure the sshd on a remote machine.
Although I'd never done sshd itself, I've done this kind of thing
a zillion times before. It looks like this: there is a configuration
file (in this case /etc/ssh/sshd-config ) that you modify. But this
doesn't change the running server; you have to notify the server that
it should reread the file. One way would be by killing the server and
starting a new one. This would interrupt service, so instead you can
send the server a different signal (in this case SIGHUP ) that tells
it to reload its configuration without exiting. Simple enough.
Except, it didn't work. I added:
Match User mjd
ForceCommand echo "I like pie!"
and signalled the server, then made a new connection to see if it
would print I like pie! instead of starting a shell. It started a
shell. Okay, I've never used Match or ForceCommand before, maybe
I don't understand how they work, I'll try something simpler. I
added:
PrintMotd yes
which seemed straightforward enough, and I put some text into
/etc/motd , but when I connected it didn't print the motd.
I tried a couple of other things but none of them seemed to work.
Okay, maybe the sshd is not getting the signal, or something? I
hunted up the logs, but there was a report like what I expected:
sshd[1210]: Received SIGHUP; restarting.
This was a head-scratcher. Was I modifying the wrong file? It semed
hardly possible, but I don't administer this machine so who knows? I
tried lsof -p 1210 to see if maybe sshd had some other config file
open, but it doesn't keep the file open after it reads it, so that was
no help.
Eventually I hit upon the answer, and I wish I had some useful piece
of advice here for my future self about how to figure this out. But I
don't because the answer just struck me all of a sudden.
(It's nice when that happens, but I feel a bit cheated afterward: I
solved the problem this time, but I didn't learn anything, so how
does it help me for next time? I put in the toil, but I didn't get
the full payoff.)
“Aha,” I said. “I bet it's because my connection is multiplexed.”
Normally when you make an ssh connection to a remote machine, it
calls up the server, exchanges credentials, each side authenticates
the other, and they negotiate an encryption key. Then the server
forks, the child starts up a login shell and mediates between the
shell and the network, encrypting in one direction and decrypting in
the other. All that negotiation and authentication takes time.
There is a “multiplexing” option you can use instead. The handshaking
process still occurs as usual for the first connection. But once the
connection succeeds, there's no need to start all over again to make a
second connection. You can tell ssh to multiplex several virtual
connections over its one real connection. To make a new virtual
connection, you run ssh in the same way, but instead of contacting
the remote server as before, it contacts the local ssh client that's
already running and requests a new virtual connection. The client,
already connected to the remote server, tells the server to allocate a
new virtual connection and to start up a new shell session for it.
The server doesn't even have to fork; it just has to allocate another
pseudo-tty and run a shell in it. This is a lot faster.
I had my local ssh client configured to use a virtual connection if
that was possible. So my subsequent ssh commands weren't going
through the reconfigured parent server. They were all going through
the child server that had been forked hours before when I started my
first connection. It wasn't affected by reconfiguration of the parent
server, from which it was now separate.
I verified this by telling ssh to make a new connection without
trying to reuse the existing virtual connection:
ssh -o ControlPath=none -o ControlMaster=no ...
This time I saw the MOTD and when I reinstated that Match command I
got I like pie! instead of a shell.
(It occurs to me now that I could have tried to SIGHUP the child
server process that my connections were going through, and that would
probably have reconfigured any future virtual connections through that
process, but I didn't think of it at the time.)
Then I went home for the day, feeling pretty darn clever, right up
until I discovered, partway through writing this article, that I can't
log in because all I get is I like pie! instead of a shell.
[Other articles in category /Unix]
permanent link
|