Haskell Global var inside loop



这是我的函数之一,涉及其他一些函数。

main' :: IO ()
main' = do putStr "Enter a string: "
yx <- getLine
let a = chunks yx
let counter = (length . concat . map pairToList) a
let c = 0
let loop = do
let b = a !! c
let kk = xx b
let c = c + 1
let q = oncemore kk
when (c /= (counter))  loop
pp(q)

我的问题将以粗体显示在底部

我将让其余的函数在这里期待新的方法来解决我的问题。最后,我有一个最终输出应该是什么样子的图像。 (我在底部重复上面的代码)

module Bigtext where
import Char
import Hugs.Prelude
import Data.List
import Control.Monad
cap :: Char -> Char
cap  c = if c >= 'a' && c <= 'z' then chr (ord c - 32) else c
letter' :: Char -> [String]
pp :: [String]->IO()
pp = putStr . concatMap (++"n")
letter' 'A' = [" AA ",
"A  A",
"AAAA",
"A  A",
"A  A"]
letter' 'B' = ["BBB ",
"B  B",
"BBB ",
"B  B",
"BBB "]
letter' 'C' = [" CCC",
"C   ",
"C   ",
"C   ",
" CCC"]
letter' 'D' = ["DDD ",
"D  D",
"D  D",
"D  D",
"DDD "]
letter' 'E' = ["EEEE",
"E   ",
"EEE ",
"E   ",
"EEEE"]
letter' 'F' = ["FFFF", 
"F   ", 
"FFF ", 
"F   ", 
"F   "]
letter' 'G' = [" GGG ", 
"G    ", 
"G  GG", 
"G   G", 
" GGG "]
letter' 'H' = ["H  H", 
"H  H", 
"HHHH", 
"H  H", 
"H  H"]
letter' 'I' = ["III", 
" I ", 
" I ", 
" I ", 
"III"]
letter' 'J' = ["    J", 
"    J", 
"    J", 
"J   J", 
" JJJ "]
letter' 'K' = ["K  K", 
"K K ", 
"KK  ", 
"K K ", 
"K  K"]
letter' 'L' = ["L   ",
"L   ",
"L   ",
"L   ",
"LLLL"]
letter' 'M' = ["M   M",
"MM MM",
"M M M",
"M   M",
"M   M"]
letter' 'N' = ["N   N",
"NN  N",
"N N N",
"N  NN",
"N   N"]
letter' 'O' = [" OOO ",
"O   O",
"O   O",
"O   O",
" OOO "]
letter' 'P' = ["PPPP ",
"P   P",
"PPPP ",
"P    ",
"P    "]
letter' 'Q' = [" QQQ  ",
"Q   Q ",
"Q   Q ",
"Q  QQ ",
" QQQQQ"]
letter' 'R' = ["RRRR ",
"R   R",
"RRRR ",
"R R  ",
"R  RR"]
letter' 'S' = [" SSS ",
"S    ",
" SSS ",
"    S",
"SSSS "]
letter' 'T' = ["TTTTTT",
"  TT  ",
"  TT  ",
"  TT  ",
"  TT  "]
letter' 'U' = ["U   U",
"U   U",
"U   U",
"U   U",
" UUU "]
letter' 'V' = ["V     V",
"V     V",
" V   V ",
"  V V  ",
"   V   "]
letter' 'W' = ["W     W",
"W     W",
"W  W  W",
" W W W ",
"  W W  "]
letter' 'X' = ["X   X",
" X X ",
"  X  ",
" X X ",
"X   X"]
letter' 'Y' = ["Y   Y",
" Y Y ",
"  Y  ",
"  Y  ",
"  Y  "]
letter' 'Z' = ["ZZZZZ",
"   Z ",
"  Z  ",
" Z   ",
"ZZZZZ"]
letter' ' ' = ["      ",
"      ",
"      ",
"      ",
"      "]
letter' c = letter' (cap c)
letter :: Char -> IO()
letter c = pp(letter' (cap c))
zipAll :: [[String]] -> [String]
zipAll = map unwords . transpose
chunk :: Int -> [a] -> [[a]]
chunk _ [] = []
chunk n xs = first : chunk n rest where (first, rest) = splitAt n xs
splitSkip :: Int -> [a] -> [[a]]
splitSkip n xs = transpose $ chunk n xs
chunks yx = words yx
pairToList :: a -> [a]
pairToList x = [x]
xx b = zipAll (map (letter' . head) (splitSkip (length b) b))
type MyString = [String]
oncemore :: MyString -> MyString
oncemore kk = kk ++ kk
main' :: IO ()
main' = do putStr "Enter a string: "
yx <- getLine
let a = chunks yx
let counter = (length . concat . map pairToList) a
let c = 0
let loop = do
let b = a !! c
let kk = xx b
let c = c + 1
let q = oncemore kk
when (c /= (counter))  loop
pp(q)

这是预期的输出:

预期产出

这就是我现在所处的位置

main' :: IO ()
main' = do putStr "Enter a string: "
yx <- getLine
let a = chunks yx
let counter = (length . concat . map pairToList) a
let c = 0
let loop c = do
let c' = c + 1
let b = a !! (c'-1)
let kk = xx b
if c' /= counter
then return kk
else loop c'
**kk <- loop c**
pp(kk)

kk <- 循环c 行中,如果我将 c 更改为一个数字,则可能会得到一个单词(取决于您输入的单词数)问题是:如何打印所有索引的? 例如,如果我有 3 个单词,如何在没有硬代码的情况下打印出来?

对不起我的英语... 谢谢你的时间。

Haskell变量不是程序员通常解释这个词的"变量",也就是说,它们不是可变的。基本上,任何Haskell变量都只是一个局部常量。因此,您的循环结构没有意义,即

let c = 0
let loop = do
...
let c = c + 1
when (c /= counter) loop

根本不起作用。

  • 实际上并没有进入循环,你只是定义循环是什么。
  • 如果你真的进入了循环,你会严重绊倒let c = c + 1。这不会修改现有的c,相反,它只是定义了一个完全独立的变量c,因为它的范围较窄,所以遮蔽了前c = 0。这种阴影绑定甚至用于定义本身,即计算运行时需要知道c的值c,它需要计算c,到哪个...等等。

你真正想要的是

let c = 0
let loop c = do
...
let c' = c + 1
when (c' /= counter) $ loop c'
loop 0  -- actually invoke the loop, starting from 0.

但即便如此,这个循环并没有真正完成任何事情——你只是在每次迭代中定义一些局部变量,但实际上从来没有对它们做任何持久影响的事情。

您可以在每次迭代中提交一些实际的IO操作,例如打印出一个大字母。你也可以从循环中得到一些结果,这似乎是你在这个问题中问的。例如,要将q的最后一个"状态"广播到外部,您需要将when(如果不满足条件,则快捷方式return ())替换为

let loop c = do
let q = ...
let c' = c + 1
if c' == counter
then return q
then loop c'
q <- loop 0

但我不同意这是明智的;相反,更好的方法是连接所有仍然以列表形式出现的字母(这不需要任何丑陋的索引/长度杂耍,也不需要任何 IO 或显式循环,只需mapconcat),然后在一个干净的putStr中打印整个结果。

整个事情可以通过以下方式完成:

module Main where
import Data.List (transpose)
import Data.Char (ord, chr, toUpper)
pp :: [String] -> IO ()
pp = putStr . unlines
letter :: Char -> [String]
{- letter definitions go here -}
-- anything else gets a square of ?'s
letter _ =  ["?????",
"?   ?",
"?   ?",
"?   ?",
"?????"]
bigify :: String -> [String]
bigify = map unwords . transpose . map (letter . toUpper)
main :: IO ()
main = do putStr "Enter a string: "
getLine >>= pp . concatMap bigify . words

main中,我们得到一行文本,将其分解成单词,对于每个单词,将单词bigify成行,连接行,然后pp整个事情。

bigify函数在其 word 参数中映射每个字符,将每个字符传递给toUpper,然后传递letter,这会将其转换为该字符的大写版本的行列表。 结果是一个列表,每个字符都有一个元素,其中每个元素都是该字符的行列表。 这被transpose到一个列表中,每行都有一个元素,其中每个元素都是该行的每个字符的片段列表。 这些元素与unwords连接以形成线条列表。

最新更新