What can be improved in my first haskell?

Here is my first Haskell program. What parts could you write better?

-- Multiplication table
-- Returns n*n multiplication table in base b

import Text.Printf
import Data.List
import Data.Char

-- Returns n*n multiplication table in base b 
mulTable :: Int -> Int -> String
mulTable n b = foldl (++) (verticalHeader n b w) (map (line n b w) [0..n])
               where 
                 lo = 2* (logBase (fromIntegral  b)  (fromIntegral n))
                 w = 1+fromInteger (floor lo)

verticalHeader :: Int -> Int -> Int -> String  
verticalHeader n b w = (foldl (++) tableHeader columnHeaders)
                        ++ "\n" 
                        ++ minusSignLine 
                        ++ "\n"
                   where
                     tableHeader = replicate (w+2) ' '
                     columnHeaders = map (horizontalHeader b w) [0..n]
                     minusSignLine = concat ( replicate ((w+1)* (n+2)) "-" )

horizontalHeader :: Int -> Int -> Int -> String
horizontalHeader b w i = format i b w

line :: Int -> Int -> Int -> Int -> String
line n b w y  = (foldl (++) ((format y b w) ++ "|" ) 
                           (map (element b w y) [0..n])) ++ "\n"

element :: Int -> Int -> Int -> Int -> String  
element b w y x = format  (y * x) b w

toBase :: Int -> Int -> [Int]
toBase b v = toBase' [] v where
  toBase' a 0 = a
  toBase' a v = toBase' (r:a) q where (q,r) = v `divMod` b

toAlphaDigits :: [Int] -> String
toAlphaDigits = map convert where
  convert n | n < 10    = chr (n + ord '0')
            | otherwise = chr (n + ord 'a' - 10)

format :: Int -> Int -> Int -> String
format v b w = concat spaces ++ digits ++ " "
               where 
                   digits  = if v == 0 
                             then "0" 
                             else toAlphaDigits ( toBase b v )
                   l = length digits
                   spaceCount = if (l > w) then  0 else (w-l) 
                   spaces = replicate spaceCount " " 
+5
source share
6 answers

Here are some suggestions:

  • To make the tabular presentation of the calculation more obvious, I would pass a list of [0..n]functions linerather than pass n.

  • I would further separate the calculation of the horizontal and vertical axes so that they are passed as arguments mulTableand not calculated there.

  • Haskell has a higher order, and almost none of the calculations are related to multiplication. So I would change the name mulTableto binopTableand pass the actual multiplication as a parameter.

  • , . \x -> format x b w , b w?

, , , . -

binopTable :: (i -> String) -> (i -> i -> i) -> [i] -> [i] -> String

- , .

- .

+11

import Text.Printf.

, , . Haskellers , , . h x = f (g x) h = f . g.

Int; (Integral a) => a .

foldl (++) x xs == concat $ x : xs: , concat , .
, foldr, , (++) is – Haskell , ( ).
, unwords unlines intercalate " " concat . map (++ "\n") , " " " ( )"; .

, w = length $ takeWhile (<= n) $ iterate (* b) 1, , . , , w = length $ toBase b n.

concat ( (replicate ((w+1)* (n+2)) "-" ) == replicate ((w+1) * (n+2)) '-' – , , .

concat spaces. Text.Printf printf "%*s " w digits?

+11

() ; :

  • HLint. HLint - , , Haskell!
    • HLint 7 . ( )
    • HLint, , .
  • HLint- :
    • concat (replicate i "-"). replicate i '-'?
  • Hoogle, , Haskell. Haskell , Hoogle .
    • ? [String] -> String, concat. .
    • unlines. , . !
  • : , Hoogle HLint, , , Haskell, , .
  • , , , , , . , , .

,

-- Returns n*n multiplication table in base b 
mulTable :: Int -> Int -> String
mulTable n b =

mulTable :: Int -> Int -> String
mulTable size base =
  • : , where, , , .

,

line :: Int -> Int -> Int -> Int -> String
line n b w y =
  concat
  $ format y b w
  : "|"
  : map (element b w y) [0 .. n]

element :: Int -> Int -> Int -> Int -> String  
element b w y x = format (y * x) b w

line :: Int -> Int -> Int -> Int -> String
line n b w y =
  concat
  $ format y b w
  : "|"
  : map element [0 .. n]
  where
    element x = format (y * x) b w
  • line mulTable where; , .
    • where, where, . , 2 4 . , , where where.

, ( ):

import Data.List
import Data.Char

mulTable :: Int -> Int -> String
mulTable size base =
  unlines $
  [ vertHeaders
  , minusSignsLine
  ] ++ map line [0 .. size]
  where
    vertHeaders =
      concat
      $ replicate (cellWidth + 2) ' '
      : map horizontalHeader [0 .. size]
    horizontalHeader i = format i base cellWidth
    minusSignsLine = replicate ((cellWidth + 1) * (size + 2)) '-'
    cellWidth = length $ toBase base (size * size)
    line y =
      concat
      $ format y base cellWidth
      : "|"
      : map element [0 .. size]
      where
        element x = format (y * x) base cellWidth

toBase :: Integral i => i -> i -> [i]
toBase base
  = reverse
  . map (`mod` base)
  . takeWhile (> 0)
  . iterate (`div` base)

toAlphaDigit :: Int -> Char
toAlphaDigit n
  | n < 10    = chr (n + ord '0')
  | otherwise = chr (n + ord 'a' - 10)

format :: Int -> Int -> Int -> String
format v b w =
  spaces ++ digits ++ " "
  where 
    digits
      | v == 0    = "0"
      | otherwise = map toAlphaDigit (toBase b v)
    spaces = replicate (w - length digits) ' '
+5

0) :-)

import System.Environment (getArgs)
import Control.Monad (liftM)

main :: IO ()
main = do
  args <- liftM (map read) $ getArgs
  case args of
    (n:b:_) -> putStrLn $ mulTable n b
    _       -> putStrLn "usage: nntable n base"

1) ghc runhaskell -Wall; hlint.

hlint ( ), ghc , Text.Printf ...

2) = 1 base = 0 base = -1

+4

, :

{-  A multiline
   comment -}

, foldl, foldl' , , , . .

+2

, , , , . , .

, , . , .

: , Integral, toAlphaDigits - " ".

+1

All Articles