72 lines
1.9 KiB
Haskell
72 lines
1.9 KiB
Haskell
import Data.Bool (bool)
|
|
import Data.List (replicate, transpose)
|
|
import Data.List.Split (chunksOf)
|
|
|
|
---------------------- JACOBI SYMBOL ---------------------
|
|
|
|
jacobi :: Int -> Int -> Int
|
|
jacobi = go
|
|
where
|
|
go 0 1 = 1
|
|
go 0 _ = 0
|
|
go x y
|
|
| even r =
|
|
plusMinus
|
|
(rem y 8 `elem` [3, 5])
|
|
(go (div r 2) y)
|
|
| otherwise = plusMinus (p r && p y) (go y r)
|
|
where
|
|
plusMinus = bool id negate
|
|
p = (3 ==) . flip rem 4
|
|
r = rem x y
|
|
|
|
|
|
--------------------------- TEST -------------------------
|
|
main :: IO ()
|
|
main = putStrLn $ jacobiTable 11 9
|
|
|
|
------------------------- DISPLAY ------------------------
|
|
jacobiTable :: Int -> Int -> String
|
|
jacobiTable nCols nRows =
|
|
let rowLabels = [1, 3 .. (2 * nRows)]
|
|
colLabels = [0 .. pred nCols]
|
|
in withColumnLabels ("" : fmap show colLabels) $
|
|
labelledRows (fmap show rowLabels) $
|
|
paddedCols $
|
|
chunksOf nRows $
|
|
uncurry jacobi
|
|
<$> ((,) <$> colLabels <*> rowLabels)
|
|
|
|
------------------- TABULATION FUNCTIONS -----------------
|
|
paddedCols ::
|
|
Show a =>
|
|
[[a]] ->
|
|
[[String]]
|
|
paddedCols cols =
|
|
let scols = fmap show <$> cols
|
|
w = maximum $ length <$> concat scols
|
|
in map (justifyRight w ' ') <$> scols
|
|
|
|
labelledRows :: [String] -> [[String]] -> [[String]]
|
|
labelledRows labels cols =
|
|
let w = maximum $ map length labels
|
|
in zipWith
|
|
(:)
|
|
((<> " ->") . justifyRight w ' ' <$> labels)
|
|
(transpose cols)
|
|
|
|
withColumnLabels :: [String] -> [[String]] -> String
|
|
withColumnLabels _ [] = ""
|
|
withColumnLabels labels rows@(x : _) =
|
|
let labelRow =
|
|
unwords $
|
|
zipWith
|
|
(`justifyRight` ' ')
|
|
(length <$> x)
|
|
labels
|
|
in unlines $
|
|
labelRow :
|
|
replicate (length labelRow) '-' : fmap unwords rows
|
|
|
|
justifyRight :: Int -> a -> [a] -> [a]
|
|
justifyRight n c = (drop . length) <*> (replicate n c <>)
|