Я не мог устоять. Вот мой порт кода Рэйфа в Haskell:
module Langford where
import Control.Applicative
import Control.Monad
import Data.Array
import Data.List
import Data.Ord
import Data.Tuple
import qualified Data.IntSet as S
langford :: Int -> [[Int]]
langford n
| mod n 4 `elem` [0, 3] = map (pairingToList n) . search $ initial n
| otherwise = []
type Variable = (Int, S.IntSet)
type Assignment = (Int, Int)
type Pairing = [Assignment]
initial :: Int -> [Variable]
initial n = [(i, S.fromList [1..(2*n-i-1)]) | i <- [1..n]]
search :: [Variable] -> [Pairing]
search [] = return []
search vs = do
let (v, vs') = choose vs
a <- assignments v
case prune a vs' of
Just vs'' -> (a :) <$> search vs''
Nothing -> mzero
choose :: [Variable] -> (Variable, [Variable])
choose vs = (v, filter (\(j, _) -> i /= j) vs)
where v@(i, _) = minimumBy (comparing (S.size . snd)) vs
assignments :: Variable -> [Assignment]
assignments (i, d) = [(i, k) | k <- S.toList d]
prune :: Assignment -> [Variable] -> Maybe [Variable]
prune a = mapM (prune' a)
prune' :: Assignment -> Variable -> Maybe Variable
prune' (i, k) (j, d)
| S.null d' = Nothing
| otherwise = Just (j, d')
where d' = S.filter (`notElem` [k, k+i+1, k-j-1, k+i-j]) d
pairingToList :: Int -> Pairing -> [Int]
pairingToList n = elems . array (1, 2*n) . concatMap positions
where positions (i, k) = [(k, i), (k+i+1, i)]
Кажется, это работает довольно хорошо. Вот некоторые моменты из GHCi:
Prelude Langford> :set +s
Prelude Langford> head $ langford 4
[4,1,3,1,2,4,3,2]
(0.03 secs, 6857080 bytes)
Prelude Langford> head $ langford 32
[32,28,31,23,26,29,22,24,27,15,17,11,25,10,30,5,20,2,21,19,2,5,18,11,10, ...]
(0.05 secs, 15795632 bytes)
Prelude Langford> head $ langford 100
[100,96,99,91,94,97,90,92,95,83,85,82,93,78,76,73,88,70,89,87,69,64,86, ...]
(0.57 secs, 626084984 bytes)