组合函数 'length' 和 'elemIndices'

Composing functions 'length' and 'elemIndices'

我编写了一个函数 count :: Char -> String -> Int 来计算 CharString 中出现的次数。代码示例:

module Main where

import Data.List

main :: IO ()
main = do
        print $ count 'a' "abcaaba"

count :: Char -> String -> Int
count = length . elemIndices

我得到的编译错误是

* Couldn't match type `Int' with `String -> Int'
  Expected type: Char -> String -> Int
    Actual type: Char -> Int
* Possible cause: `(.)' is applied to too many arguments
  In the expression: length . elemIndices
  In an equation for `count': count = length . elemIndices

好的,我可以写 count x y = length $ elemIndices x y 这行得通。但我认为我们有

(1) (.) :: (b -> c) -> (a -> b) -> a -> c

(2) elemIndices :: Eq a => a -> [a] -> [Int]

(3) length :: [a] -> Int

如果count是(2)和(3)的组合,那么在(1)中显然需要a = Char -> [Char]c = Int。如果 b = [Int] 我们得到

(1') (.) :: ([Int] -> Int) -> (Char -> [Char] -> [Int]) -> Char -> [Char] -> Int

这意味着我可以组合(2)和(3)得到Char -> [Char] -> Int

问题:

  1. 为什么我写的作文编译不通过?
  2. 我的推理哪里出错了?

-> 在类型中是右结合的:

elemIndices :: Eq a => a -> [a] -> [Int]

表示

elemIndices :: Eq a => a -> ([a] -> [Int])

当您在 (.) :: (b -> c) -> (a' -> b) -> a' -> c 的右侧使用 elemIndices 时,您有

  • a' = a
  • b = [a] -> [Int]

这就是问题所在,因为 length 没有将 [a] -> [Int](函数)作为输入;它需要一个列表。


你可以做的是:

count x y = length (elemIndices x y)

这与(根据 (.) 的定义)相同:

count x y = (length . elemIndices x) y

减少埃塔:

count x = length . elemIndices x

你可能应该到此为止,因为这是事情变得有点疯狂的地方。


前缀表示法:

count x = (.) length (elemIndices x)

(.)的定义:

count x = ((.) length . elemIndices) x

减少埃塔:

count = (.) length . elemIndices

或使用运算符部分:

count = (length .) . elemIndices

等等,还有更多!

前缀表示法:

count = (.) ((.) length) elemIndices

(.)的定义:

count = (((.) . (.)) length) elemIndices

删除多余的括号:

count = ((.) . (.)) length elemIndices

前缀表示法:

count = (.) (.) (.) length elemIndices

美到极致。