错误 - 推断类型不够通用

时间:2017-04-03 11:55:19

标签: function haskell types

我试图在Haskell中编写一个简单的高阶函数,它有两个参数:

  1. 任何类型的功能列表。
  2. (数字或StringBool ean等)的列表 - >任何类型
  3. 该函数应将第一个列表中的所有函数应用于第二个列表中的所有元素,将值存储在列表中,然后返回列表。该计划的一个例子是:

    Main> apply [(^2),(^3),(^4)] [2..8]
    --result: --[4,8,9,16,25,27,32,36,49,64,81,125,128,216,256,343,512,625,1296,2401,4096]
    

    该功能的类型必须是:

    apply :: Ord u => [v->u]->[v]->[u]
    

    为此,我使用了两个辅助函数并使用了递归。我的计划是这样的:

    apply :: Ord u => [v->u]->[v]->[u]             
    apply p s = myApply p s []              --line 59--
    
    myApply :: Ord u => [v->u]->[u]->[u]->[u]
    myApply f_list num_list starterlist
        | null f_list = starterlist
        | otherwise = myApply (tail f_list) (num_list) ( applyList (head     f_list) num_list starterlist )
    
    applyList :: Ord u => (v->u)->[u]->[u]->[u]
    applyList f num_list starterlist
        | null num_list = starterlist
        | otherwise = applyList f (tail num_list) ( (head num_list) :     starterlist )
    

    我收到错误:

    ERROR "Lab2.hs":59 - Inferred type is not general enough
    *** Expression    : applyList
    *** Expected type : Ord a => (b -> a) -> [a] -> [b] -> [a]
    *** Inferred type : Ord a => (a -> a) -> [a] -> [a] -> [a]
    

    知道类型有什么问题吗?

2 个答案:

答案 0 :(得分:4)

您收到此错误的原因是有冲突的类型签名

apply :: Ord u => [v->u]->[v]->[u]
apply p s = myApply p s []              --line 59--

myApply :: Ord u => [v->u]->[u]->[u]->[u]
myApply f_list num_list starterlist
    | null f_list = starterlist
    | otherwise = myApply (tail f_list) (num_list) ( applyList (head     f_list) num_list starterlist )

如您所见,apply函数会立即调用myApply函数。由于myApply具有签名[v -> u] -> [u] -> [u] -> [u],因此apply只能拥有签名[v->u] -> [u] -> [u]

快速解决方法是概括 myApplymyApplyList[v -> u] -> [v] -> [u] -> [u]。现在,编译还会检测到您在applyList函数中发生的错误:您忘记在f上致电head num_list。所以你可以修复它并获得以下代码:

apply :: Ord u => [v->u]->[v]->[u]             
apply p s = myApply p s []              --line 59--

myApply :: Ord u => [v->u]->[v]->[u]->[u]
myApply f_list num_list starterlist
    | null f_list = starterlist
    | otherwise = myApply (tail f_list) (num_list) ( applyList (head     f_list) num_list starterlist )

applyList :: Ord u => (v->u)->[v]->[u]->[u]
applyList f num_list starterlist
    | null num_list = starterlist
    | otherwise = applyList f (tail num_list) ( (f (head num_list)) :     starterlist )

尽管如此,这段代码非常不光彩并且使用了很多函数和参数。您可以使用单个列表解析完全替换它:

apply :: [v -> u] -> [v] -> [u]
apply fs xs = [f x | f <- fs, x <- xs]

根据您的评论,您还必须在过程的后期对值进行排序,您可以使用sort :: Ord a => [a] -> [a]内置来完成此操作:

-- sorting variant
apply :: Ord u => [v -> u] -> [v] -> [u]
apply fs xs = sort [f x | f <- fs, x <- xs]

这会产生所需的结果:

Prelude Data.List> (\fs xs -> sort [f x | f <- fs, x <- xs]) [(^2),(^3),(^4)] [2..8]
[4,8,9,16,16,25,27,36,49,64,64,81,125,216,256,343,512,625,1296,2401,4096]

答案 1 :(得分:4)

主题的变化:接受Willem的评论,指出这是一个非常复杂的代码(难以分析)我从一个更简单的代码开始,而没有说明任何类型,首先得到一个简单的工作案例(即产生预期输出的函数),仍然使用辅助函数和递归:

apply fs     []  = []
apply []     xs  = []
apply (f:fs) xs  = (helper f xs) ++ (apply fs xs)

helper f []     = []
helper f (x:xs) = f x : helper f xs

然后我会要求Haskell编译器向我提供有关它推断出的类型签名的信息:

*Main> :t apply
apply :: [t1 -> t] -> [t1] -> [t]

通过意识到t1 -> t映射到您的v->u,我可以看到类型签名也可以写成:

[v -> u] -> [v] -> [u] 

helper执行类似操作,最终会得到以下结果:

apply :: [v->u] -> [v] -> [u]             
apply fs     []  = []
apply []     xs  = []
apply (f:fs) xs  = (helper f xs) ++ (apply fs xs)

helper :: (v -> u) -> [v] -> [u]
helper f []     = []
helper f (x:xs) = f x : helper f xs

从这里开始,您可以通过添加Ord约束,并建立排序功能等来实现自己的方式。