Haskell 中的基本 "apply twice" hello world 类型不匹配

Type mismatch on basic "apply twice" hello world in Haskell

最小代码:

twice :: (a -> a) -> a -> a
twice f = f . f

main = do
   return twice ++ "H"

产生的错误:

stack runhaskell "c:\Users\FruitfulApproach\Desktop\Haskell\test.hs"

C:\Users\FruitfulApproach\Desktop\Haskell\test.hs:5:1: error:
    * Couldn't match expected type `IO t0'
                  with actual type `[(a0 -> a0) -> a0 -> a0]'
    * In the expression: main
      When checking the type of the IO action `main'
  |
5 | main = do
  | ^

C:\Users\FruitfulApproach\Desktop\Haskell\test.hs:6:20: error:
    * Couldn't match type `Char' with `(a -> a) -> a -> a'
      Expected type: [(a -> a) -> a -> a]
        Actual type: [Char]
    * In the second argument of `(++)', namely `"H"'
      In a stmt of a 'do' block: return twice ++ "H"
      In the expression: do return twice ++ "H"
    * Relevant bindings include
        main :: [(a -> a) -> a -> a]
          (bound at C:\Users\FruitfulApproach\Desktop\Haskell\test.hs:5:1)
  |
6 |    return twice ++ "H"
  |                    ^^^

我自己如何从逻辑上解决这个问题?显然这是我做错的事情。我是否遗漏了每个示例都应该包含的序言?

正如 RobinZigmond 在评论中提到的,你不能写 twice ++ "H"。这意味着,“获取函数 twice,并将字符串 "H" 附加到它”。这显然是不可能的,因为 ++ 只能将字符串和列表附加在一起。我怀疑你的意思是twice (++ "H")。这采用函数 (++ "H"),它将 "H" 附加到其参数的末尾,并且 运行 将其添加两次。

但是即使你这样做了,还是有问题。看看如果你这样做创建的程序:

twice :: (a -> a) -> a -> a
twice f = f . f

main = do
   return (twice (++ "H"))

即使这个程序编译通过了,它也没有做任何事情!您已将 twice (++ "H")) 设置为 main 的 return 值,但始终忽略 main 的 return 值。为了产生输出,您需要使用 putStrLn 而不是 return:

twice :: (a -> a) -> a -> a
twice f = f . f

main = do
   putStrLn (twice (++ "H"))

但是这个程序也不行! twice (++ "H") 是函数,无法打印。此函数必须应用于一个值才能产生结果:

twice :: (a -> a) -> a -> a
twice f = f . f

main = do
   putStrLn (twice (++ "H") "Starting value")

这个程序最终应该可以运行,在 运行 时给出 Starting valueHH 的输出。