开发者

Haskell: problem with recursion

开发者 https://www.devze.com 2023-02-17 02:01 出处:网络
I am trying to format text to be in the shape of a rectangle; currently I have been able to get it properly left justified, but the last line does not extend as far as possible.

I am trying to format text to be in the shape of a rectangle; currently I have been able to get it properly left justified, but the last line does not extend as far as possible.

I am trying to calculate the optimum field width in order to minimise or remove this entirely.

I am totally stuck. The code below shows the relevant functions. At the moment it gets stuck in an infinite loop. Where am I going wrong?

On a side note, what is the best way of debugging Haskell code? (Yes, I'm very new to this.)

optimumFieldWidth is supposed to compare line lengths until the length of the top line is equal to that of the bottom line, then return the field width which causes this to be true.

module Main where

import System
import Data.List

main = do 
  (f:_) <- getArgs
  xs <- getContents
  putStr (sho开发者_如何学Cw (bestFieldWidth maxLineLength xs))

bestFieldWidth :: Int -> String -> Int
bestFiledWidth _ [] = 0
bestFieldWidth lineLength xs
  | length (last input) == length (head input) = lineLength
  | otherwise = bestFieldWidth (length (head (rect (lineLength-1) xs))) xs
  where input = lines xs

rect :: Int -> String -> [String]
rect _ [] = []
rect lineLength xs
  | length input <= len = [input]
  | otherwise           = take len input : rect len (drop len input)
  where input = trim xs
        len   = bestFieldWidth lineLength xs

maxLineLength :: Int
maxLineLength = 40

All responses are appreciated. Thank you.


I thought I'd put the actual solution here in case any other nutters wish to do this. Please bear in mind that it was written by a moron so it probably isn't the most elegant solution.

maxFieldWidth :: Int
maxFieldWidth = 30

rect :: String -> String
rect xs  = (unlines (chunk (bestFieldWidth (maxFieldWidth) (lines input)) input))
  where input = itemsReplace '\n' ' ' xs

--Should be called with the point maximum desired width as n
bestFieldWidth :: Int -> [String] -> Int
bestFieldWidth _ [] = error "bestFieldWidth: Empty List"
bestFieldWidth n xs
  | n == 6 = 6
  | 1 == (length (last input)) = n
  | otherwise = (bestFieldWidth (n-1) xs)
  where input = chunk n (unlines xs)

chunk :: Int -> [a] -> [[a]]
chunk n [] = []
chunk n xs = ys : chunk n zs
  where (ys,zs) = splitAt n xs

itemsReplace :: Eq a => a -> a -> [a] -> [a]
itemsReplace _ _ [] = []
itemsReplace c r (x:xs)
  | c == x    = r:itemsReplace c r xs
  | otherwise = x:itemsReplace c r xs


It seems that the condition length (last input) == length (head input) once false never goes true in subsequent calls to area, thus making this function always take the otherwise branch and keep calling itself indefinitely with the same values of xs and thus input.

Possible cause of this is that you use the lines function, which splits a string with newline characters, in a way not dependent on lineLength and inconsistent with your line-splitting in the rect function.


In answer to your side note, here is an excellent guide to debugging Haskell: http://cgi.cse.unsw.edu.au/~dons/blog/2007/11/14

There's also Debug.Trace, which allows you to insert print statements. It should of course only be used while debugging, because it makes your function have side effects.

http://hackage.haskell.org/packages/archive/base/latest/doc/html/Debug-Trace.html

0

精彩评论

暂无评论...
验证码 换一张
取 消