试图了解为什么在Haskell中使用文件夹的此功能无法正常工作 [英] Trying to understanding why this function using foldr in Haskell isnt working

查看:66
本文介绍了试图了解为什么在Haskell中使用文件夹的此功能无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我是Haskell的新手,可以使用WikiBooks学习它.在高阶函数章节中,使用了以下示例.

So I'm new to Haskell and learning it using WikiBooks. And in the higher order functions chapter, there is the following example used.

echoes = foldr (\ x xs -> (replicate x x) ++ xs) []

所以我尝试运行它,但是它给我一个如下错误:

So I tried running it, but it gives me an error as follows :

 * Ambiguous type variable `t0' arising from a use of `foldr'
  prevents the constraint `(Foldable t0)' from being solved.
  Relevant bindings include
    echoes :: t0 Int -> [Int] (bound at HavingFun.hs:107:1)
  Probable fix: use a type annotation to specify what `t0' should be.
  These potential instances exist:
    instance Foldable (Either a) -- Defined in `Data.Foldable'
    instance Foldable Maybe -- Defined in `Data.Foldable'
    instance Foldable ((,) a) -- Defined in `Data.Foldable'
    ...plus one other
    ...plus 29 instances involving out-of-scope types
    (use -fprint-potential-instances to see them all)
* In the expression: foldr (\ x xs -> (replicate x x) ++ xs) []
  In an equation for `echoes':
      echoes = foldr (\ x xs -> (replicate x x) ++ xs) []

然后,如果我将其编写如下,那么它将起作用.

And then if I write it as follows, it works.

echoes lis = foldr (\ x xs -> (replicate x x) ++ xs) [] lis

对此我感到困惑,我认为这与函数的点无关定义有关吗? 请在这里说明问题所在. 我正在学习的地方的链接- https://en.wikibooks.org/wiki/Haskell/Lists_III

I am confused about this and I think this is somehow related point free definitions of functions ? Please clarify what the problem is there here. The link from where I'm learning - https://en.wikibooks.org/wiki/Haskell/Lists_III

推荐答案

tl; dr

只要总是写显式类型签名,那么您就可以避免出现此类奇怪的问题.

tl;dr

just always write explicit type signatures, then you're safe(r) from weird problems like that.

正常工作但现在不起作用的原因foldr以前具有签名

foldr :: (a -> b -> b) -> b -> [a] -> b

这是WikiBooks假定的,但是在较新的GHC中,它实际上具有严格更通用的签名

which is what the WikiBooks assumes, but in newer GHC it actually has the strictly more general signature

foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

通过选择t ~ [],旧版本 就是其中的特例.他们更改它的原因是,您还可以折叠其他容器,例如数组或地图.实际上,在您的代码中

The old version is a special case of this, by simply choosing t ~ []. The reason they changed it is that you can also fold over other containers, such as arrays or maps. In fact, in your code

echoes = foldr (\ x xs -> (replicate x x) ++ xs) []

也没有要求输入容器为列表的东西,因此实际上与签名一起使用会很好

there's nothing the requires the input container to be a list, either, so it would in fact work perfectly well with the signature

echoes :: Foldable t => t Int -> [Int]

...同样,[Int] -> [Int]是特例,因此该函数可以用作

...of which, again, [Int] -> [Int] is a special case, so that function could then be used as

> echoes [1,2,3]
[1,2,2,3,3,3]

但也

> echoes $ Data.Map.fromList [('a',2), ('c',5), ('b',1)]
[2,2,1,5,5,5,5,5]

或者您可以为该功能提供特定于列表的签名

Or you could have given the function the list-specific signature

echoes' :: [Int] -> [Int]
echoes' = foldr (\x xs -> (replicate x x) ++ xs) []

该功能在[1,2,3]上相同,但是不能接受Map.

That works just the same on [1,2,3] but can't accept a Map.

现在的问题是,GHC为什么不自己推断任何一个签名?好吧,如果必须选择一个,它应该是更通用的Foldable版本,因为人们可能需要将其与其他容器一起使用,并且不想继续重复Foldable t =>量词.但是,这与另一个Haskell规则相矛盾,单态限制.由于您的echoes实现不能明确接受任何参数(只能自由地进行接收),因此它是常量应用形式,并且除非明确指定为多态,否则独立的CAF应该具有单态类型.因此,您遇到的错误消息是:GHC确实希望它是单态的,但它没有限制什么具体Foldable容器选择的信息.

The question is now, why does GHC not infer either of those signatures by itself? Well, if it had to choose one, it should be the more general Foldable version, because people might need to use this with other containers and wouldn't want to keep repeating the Foldable t => quantifier. However, this contradicts another Haskell rule, the monomorphism restriction. Because your echoes implementation doesn't explicitly accept any parameters (it only does that point-freely), it is a constant applicative form, and a standalone CAF is supposed to have monomorphic type unless explicitly specified to be polymorphic. Thus the error message you ran into: GHC really wants this to be monomorphic, but it has no information that restricts what concrete Foldable container to pick.

有四种解决方法:

  • 正如您所注意到的,通过将参数显式引入范围,echoes不再是CAF,因此GHC可以推断出多态类型:

  • As you noticed, by bringing the argument explicitly in scope, echoes is not a CAF anymore and therefore GHC infers the polymorphic type:

echoes'' l = foldr (\x xs -> (replicate x x) ++ xs) [] l

> :t echoes''
echoes'' :: Foldable t => t Int -> [Int]

  • 通过禁用单态性限制,GHC不再关心它是否是CAF,而只是给它一个更通用的类型,而与之无关:

  • By disabling the monomorphism restriction, GHC won't care anymore whether it's CAF and just give it the more general type regardless:

    {-# LANGUAGE NoMonomorphismRestriction #-}
    echoes''' = foldr (\x xs -> (replicate x x) ++ xs) []
    

    > :t echoes'''
    echoes''' :: Foldable t => t Int -> [Int]

  • 已淘汰 如果您打开-XExtendedDefaultingRules扩展名,GHC将自动选择[]作为CAF的具体单形容器:

  • Discouraged If you turn on the -XExtendedDefaultingRules extension, GHC will automatically choose [] as the concrete monomorphic container for the CAF:

    {-# LANGUAGE ExtendedDefaultRules #-}
    echoes'''' = foldr (\x xs -> (replicate x x) ++ xs) []
    

    > :t echoes''''
    echoes'''' :: [Int] -> [Int]

    GHCi默认情况下启用了-XExtendedDefaultingRules,因此,如果您仅在GHCi提示符下声明该功能,也会发生这种情况.

    GHCi has -XExtendedDefaultingRules enabled by default, so that's what also happens if you just declare the function in the GHCi prompt.

    强烈建议 如果您明确指定签名,则您和GHC都将确切知道其意图并相应地举止,而无需任何特殊的GHC扩展.

    echoes :: Foldable t => t Int -> [Int]
    echoes = foldr (\x xs -> (replicate x x) ++ xs) []
    
    echoes' :: [Int] -> [Int]
    echoes' = foldr (\x xs -> (replicate x x) ++ xs) []
    

    > :t echoes
    echoes :: Foldable t => t Int -> [Int]
    > :t echoes'
    echoes' :: [Int] -> [Int]

  • 这篇关于试图了解为什么在Haskell中使用文件夹的此功能无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆