【发布时间】:2017-07-16 16:04:40
【问题描述】:
我正在尝试编写一个函数,该函数接受 String 和 Int 并返回该字符串“int”次。那就是:
duplicate :: String -> Int -> String
如果我写duplicate "Hello" 3,输出应该是"HelloHelloHello"。
【问题讨论】:
标签: haskell
我正在尝试编写一个函数,该函数接受 String 和 Int 并返回该字符串“int”次。那就是:
duplicate :: String -> Int -> String
如果我写duplicate "Hello" 3,输出应该是"HelloHelloHello"。
【问题讨论】:
标签: haskell
轻松:
duplicate :: String -> Int -> String
duplicate string n = concat $ replicate n string
$ 是 a function of type (a -> b) -> a -> b。该语言允许以中缀形式使用具有非字母数字名称的函数(作为运算符)。即,上面的函数体与下面的表达式完全一致:
($) concat (replicate n string)
$ 所做的只是让您摆脱大括号。这意味着上述表达式只是以下表达式的替代:
concat (replicate n string)
【讨论】:
$ 操作只是函数应用。只有它的优先级最低,并且是右关联而不是左关联。
duplicate的类型签名更改为[a] -> Int -> [a]。这样你就可以将它用于任何列表。
n 作为第一个参数是有意义的,因为它允许您编写像putStrLn . duplicate 3 这样的函数。关于这一点,@benharris,我认为你应该阅读Learn You A Haskell。
String 只是Char 列表的同义词,列表类型为Monad。因此
duplicate :: Int -> String -> String
duplicate n str = [1..n] >>= const str
或者,如果您想获得所有积分
duplicate = (. const) . (>>=) . enumFromTo 1
编辑
按照 cmets 的建议
duplicate n str = [1..n] >> str
或
duplicate = (>>) . enumFromTo 1
【讨论】:
您可以使用replicate 和concat,如下所示:
duplicate :: [a] -> Int -> [a]
duplicate = flip $ (concat .) . replicate
-- or as larsmans suggested:
duplicate :: [a] -> Int -> [a]
duplicate = (concat .) . flip replicate
然后将其用作duplicate "Hello" 3。
【讨论】:
(concat .) . flip replicate.
(.) 会出现在它们所在的地方吗?他们在做什么?为什么它们是必要的?另一方面,let (.:) = fmap fmap fmap in concat .: flip replicate 是使用fmap fmap fmap 或(.).(.) 组合具有两个参数的函数的示例。这是一个您可以在其他地方重复使用的习语,而不仅仅是运行 pointfree 的输出。
您可以使用模式匹配。
duplicate _ 0 = []
duplicate xs n = xs ++ duplicate xs (n-1)
或
duplicate xs n | n==0 = []
| otherwise = xs ++ duplicate xs (n-1)
【讨论】:
concat .: flip replicate 除了内联。我怀疑它们在优化后会编译到相同的核心。
再次尝试,使用递归
duplicate s n = if n <= 1 then s else duplicate (n-1) s ++ s
虽然有点不清楚如果 n 为负数或零,该函数应该做什么。所以我选择返回字符串本身。
【讨论】: