编写函数'length'和'elemIndices'

时间:2017-05-01 11:02:59

标签: haskell function-composition

我编写了一个函数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. 我的推理在哪里出错?

1 个答案:

答案 0 :(得分:5)

类型中的

->是右关联的:

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

装置

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

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

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

这就是事情发生的原因,因为length不会将[a] -> [Int](一个函数)作为输入;它想要一个清单。

你能做的是:

count x y = length (elemIndices x y)

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

count x y = (length . elemIndices x) y

Eta减少:

count x = length . elemIndices x

你应该停在这里,因为这是事情变得有点疯狂的地方。

前缀表示法:

count x = (.) length (elemIndices x)

(.)的定义:

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

Eta减少:

count = (.) length . elemIndices

或使用操作员部分:

count = (length .) . elemIndices

但等等,还有更多!

前缀表示法:

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

(.)的定义:

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

删除多余的parens:

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

前缀表示法:

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

最大的美容成就。