【问题标题】:In Haskell how can you multiply a string?在 Haskell 中,如何将字符串相乘?
【发布时间】:2017-07-16 16:04:40
【问题描述】:

我正在尝试编写一个函数,该函数接受 StringInt 并返回该字符串“int”次。那就是:

duplicate :: String -> Int -> String

如果我写duplicate "Hello" 3,输出应该是"HelloHelloHello"

【问题讨论】:

    标签: haskell


    【解决方案1】:

    轻松:

    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)
    

    【讨论】:

    • 非常感谢!我以前见过 concat 使用过,这是我的第一个猜测......但是 $ 符号在这种情况下有什么作用?
    • @benharris $ 操作只是函数应用。只有它的优先级最低,并且是右关联而不是左关联。
    • 您应该将duplicate的类型签名更改为[a] -> Int -> [a]。这样你就可以将它用于任何列表。
    • @AaditMShah 翻转参数也是有意义的。根本不创建这样一个基本的组合功能也是一种选择。问题是我们在解释琐碎的东西时要触及多少主题。初学者很容易负担过重。
    • 是的。将n 作为第一个参数是有意义的,因为它允许您编写像putStrLn . duplicate 3 这样的函数。关于这一点,@benharris,我认为你应该阅读Learn You A Haskell
    【解决方案2】:

    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
    

    【讨论】:

      【解决方案3】:

      您可以使用replicateconcat,如下所示:

      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 的输出。
      • @ReinHenrichs 确实如此。如果您有兴趣将无点编程发挥到极致,请查看以下答案:stackoverflow.com/a/20279307/783743
      【解决方案4】:

      您可以使用模式匹配。

      duplicate _ 0 = []
      duplicate xs n = xs ++ duplicate xs (n-1)
      

      duplicate xs n  | n==0 = []
                      | otherwise = xs ++ duplicate xs (n-1)
      

      【讨论】:

      • 这完全等同于 concat .: flip replicate 除了内联。我怀疑它们在优化后会编译到相同的核心。
      • 其实这对于不懂 monads、point-free 风格等的初学者来说是一个很好的答案。
      【解决方案5】:

      再次尝试,使用递归

      duplicate s n = if n <= 1 then s else duplicate (n-1) s ++ s

      虽然有点不清楚如果 n 为负数或零,该函数应该做什么。所以我选择返回字符串本身。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多