简体   繁体   English

在Haskell中创建字符串列表

[英]Create List of Strings in Haskell

I am making the pilgrimage from Java to Haskell. 我正在从Java到Haskell朝圣。 Broadly speaking, I get the main concepts behind Haskell. 从广义上讲,我得到了Haskell背后的主要概念。 Reading all the tutorials and books 'makes sense' but I am getting stuck writing my own code from scratch. 阅读所有教程和书籍是有道理的,但我从头开始编写自己的代码。

I want to create 1000 files on the file system with names 我想在文件系统上创建1000个带有名称的文件

"myfile_1.txt" ... "myfile_1000.txt" “myfile_1.txt”...“myfile_1000.txt”

and each containing some dummy text. 每个都包含一些虚拟文本。

so far I have worked out the whole IO thing, and realise I need to build a list of Strings 1000 elements long. 到目前为止,我已经完成了整个IO的事情,并意识到我需要构建一个长度为1000的字符串列表。 So I have: 所以我有:

buildNamesList :: [] -> []
buildNamesList ???

Once I have the List I can call the writefile method on each element. 一旦我有了List,我就可以在每个元素上调用writefile方法。 What I can't figure out is how to add a number to the end of a String to get each fileName because I can't have an int i = 0, i ++ construct in Haskell. 我无法弄清楚的是如何在String的末尾添加一个数字来获取每个fileName,因为我在Haskell中不能有一个int i = 0,i ++构造。

I am a bit out of my depth here, would appreciate some guidance, thanks 我在这里有点超出我的深度,会感谢一些指导,谢谢

One possible solution: 一种可能的方案:

buildNamesList = map buildName [1..1000]
  where buildName n = "myfile_" ++ show n ++ ".txt"
import Control.Applicative

fileNames = ("myFile_"++) <$> (++".txt")  <$> show <$> [1..1000]

how do I then traverse over it, pluck out the String at element n and then pass it into another function? 然后我如何遍历它,在元素n处取出String然后将其传递给另一个函数?

No! 没有! "Plucking out" something from a list in inefficient. 从列表中“抽出”效率低下的东西。 You don't want to worry about how to get to each element, then do something with it. 你不想担心如何获得每个元素,然后用它做一些事情。 That's necessary in imperative languages because they don't have a proper abstraction over what "sequencing actions" means – it's just something magical built into the language. 这在命令式语言中是必要的,因为它们没有对“排序动作”的含义进行适当的抽象 - 它只是语言内置的神奇内容。 Haskell has much more well-specified, mathematically sound and type-safe magic for that ; Haskell有更明确的,数学上合理的声音和类型安全的魔力 ; as a result you don't need loops and suchlike. 因此,你不需要循环等。

You know what to do with each element ( String -> IO () ), and you know where the data comes from ( [String] ). 您知道如何处理每个元素( String -> IO () ),并且您知道数据来自何处( [String] )。 You also know what should eventually happen ( IO () ). 你也知道最终应该发生什么( IO () )。 So the combinator you're looking for has type ( String -> IO() ) -> [String] -> IO () , though obviously it doesn't really depend on the data being Strings, so let's simplify that to (a -> IO()) -> [a] -> IO() . 所以你正在寻找的组合器有类型( String -> IO() ) -> [String] -> IO () ,但显然它并不真正依赖于数据是字符串,所以让我们简化为(a -> IO()) -> [a] -> IO() You can look that up on Hoogle , which offers amongst sume rubbish mapM_ and forM_ , both of which do what you want: 你可以在Hoogle上查看 ,它提供mapM_垃圾mapM_forM_ ,两者都可以做你想要的:

mapM_ (\filename -> writeFile filename "bla") filenamesList

or 要么

forM_ filenamesList $ \filename ->
   writeFile filename "bla"

Sometimes I think of foldr as bearing some resemblance to a for loop. 有时我认为foldrfor循环有一些相似之处。 Here's something kind of like the i++ construct, applying i inside a loop: 这里有点像i++构造,在循环中应用i

foldr (\i accum -> ("myfile_" ++ show i ++ ".txt") : accum) [] [1..1000]


Another way could be zipWith , which applies a function to combine two lists: 另一种方法可能是zipWith ,它应用一个函数来组合两个列表:

zipWith (\a b -> a ++ show b ++ ".txt") (repeat "myfile_") [1..1000] 

or 要么

zipWith ($) (repeat (("myfile_" ++) . (++ ".txt") . show)) [1..1000]


And here's a recursive example, too, applied as fileList "myfile_" ".txt" [1..1000] : 这里也是一个递归的例子,应用为fileList "myfile_" ".txt" [1..1000]

fileList _     _   []     = [] 
fileList fName ext (x:xs) = (fName ++ show x ++ ext) : fileList fName ext xs

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM