简单的Haskell编译错误不明白

use*_*374 2 haskell compiler-errors ghc

我目前正在学习Haskell.我正在尝试编写一个函数,给定两个n个不同元素的列表,如果一个是另一个的排列,则返回true.我这样做是为了练习.

我先把它写成:

isPermut :: (Eq a)=>[a]->[a]->Bool
isPermut u v = foldl (\acc x -> acc && (elem x u)) True v
Run Code Online (Sandbox Code Playgroud)

这似乎有效.我现在尝试在没有lambda表达式的情况下重写它.所以我尝试:

isPermut :: (Eq a)=>[a]->[a]->Bool
isPermut u v = foldl (&& (flip $ elem u)) True v
Run Code Online (Sandbox Code Playgroud)

这给了我一个编译错误:

Couldn't match expected type `b0 -> Bool' with actual type `Bool'
Expected type: Bool -> b0 -> Bool
  Actual type: Bool -> Bool
In the first argument of `foldl', namely `(&& (flip $ elem u))'
In the expression: foldl (&& (flip $ elem u)) True v
Run Code Online (Sandbox Code Playgroud)

这个错误是什么意思?在没有lambda的情况下编写函数的正确方法是什么?谢谢.

Tik*_*vis 7

折叠必须采用两个参数的函数.你给了一个参数的函数,因为(&& whatever)它是相同的\ x -> x && whatever.

要在这里不使用lambda,你需要一些方法来组成&&一个双参数函数,(`elem` u)一个单参数函数.(注意(`elem` u)(flip elem) uor 相同\ x -> elem x u.)

  • 很公平,但是如果你还不是很熟悉这些奇怪的技巧(比如使用`.`部分),那么这种无表情的表达方式很难解决.当我必须这样做时,我通常会问`pointfree`,然后决定结果是否易于理解,如果不是,那么我就避免使用它.当试图用'ap`和`= <<`来记住` - >`monad技巧时,它会特别有用(相反,要记住哪一个把参数放在哪个顺序). (2认同)

Dan*_*ner 7

让我们一步一步做.

\acc x -> acc && (elem x u)
= { write (&&) in prefix form }
\acc x -> (&&) acc (elem x u)
= { definition of flip }
\acc x -> (&&) acc (flip elem u x)
= { definition of (.) }
\acc x -> ((&&) acc . flip elem u) x
= { eta reduction }
\acc -> (&&) acc . flip elem u
= { write (.) in prefix form }
\acc -> (.) ((&&) acc) (flip elem u)
= { definition of flip }
\acc -> flip (.) (flip elem u) ((&&) acc)
= { definition of (.) }
\acc -> (flip (.) (flip elem u) . (&&)) acc
= { eta reduction }
flip (.) (flip elem u) . (&&)
= { syntax sugar for sections }
(. flip elem u) . (&&)
Run Code Online (Sandbox Code Playgroud)