Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
导出组合函数的推断类型Haskell:特别是(.)map uncurry_Haskell_Types_Ghci_Unification_Inferred Type - Fatal编程技术网

导出组合函数的推断类型Haskell:特别是(.)map uncurry

导出组合函数的推断类型Haskell:特别是(.)map uncurry,haskell,types,ghci,unification,inferred-type,Haskell,Types,Ghci,Unification,Inferred Type,这里有很多关于导出组合函数的推断类型的线程,但我仍然相当困惑。我发现的所有帖子都没有对如何统一类型给出一般性的解释 我的一本考试学习指南有问题,我很难弄清楚 8) (.)map uncurry的推断类型是什么::\uuuuuuuuuuuuuuuuuuuuuu 我大部分时间都能推导出推断的类型,但我仍然有点困惑。例如,我知道要获得(.)map uncurry的答案,首先需要派生map uncurry的类型。这是我能做到的 鉴于以下类型 map :: (a -> b) -> [a] -

这里有很多关于导出组合函数的推断类型的线程,但我仍然相当困惑。我发现的所有帖子都没有对如何统一类型给出一般性的解释

我的一本考试学习指南有问题,我很难弄清楚

8) (.)map uncurry的推断类型是什么::\uuuuuuuuuuuuuuuuuuuuuu

我大部分时间都能推导出推断的类型,但我仍然有点困惑。例如,我知道要获得(.)map uncurry的答案,首先需要派生map uncurry的类型。这是我能做到的

鉴于以下类型

map  :: (a -> b) -> [a] -> [b]
uncurry :: (a -> b -> c) -> (a, b) -> c 
我用uncurry so统一了map中的函数(a->b)

a = a → b → c
b = (a, b) → c
然后答案是map[a]->[b]的另一半,新的值是a和b so

map uncurry :: [ a -> b -> c ] -> [ (a, b) -> c]
那么你需要统一

(.)  :: (b -> c) -> (a -> b) -> a -> c
map uncurry :: [ a -> b -> c ] -> [ (a, b) -> c]
答案应该是

(.) map uncurry :: (a -> b1 -> b) -> [(a, b1)] -> [b]
但我不明白b1是从哪里来的,也不知道它是怎么做的。 我想我真正需要的是对类型统一的解释。统一两种类型的方法是什么?我如何知道两种类型是否不能统一

如果有人能一步一步地解释如何推导(.)map uncurry,我将不胜感激。

(.)map uncurry
相当于
(.)map uncurry
map
功能不应用于
uncurry
,它被传递到
()
。然后,结果(希望可以推断为一个函数)作为参数接收
uncurry

至于
b1
的来源,别忘了类型变量名并不重要,您可以重命名它们,只要您以类似方式重命名给定类型变量的所有引用。因此:

(.) map uncurry :: (a -> b1 -> b) -> [(a, b1)] -> [b]
相当于:

(.) map uncurry :: (apple -> pear -> plum) -> [(apple, pear)] -> [plum]
(.)map uncurry
相当于
(.)map)uncurry
map
功能不应用于
uncurry
,它被传递到
()
。然后,结果(希望可以推断为一个函数)作为参数接收
uncurry

至于
b1
的来源,别忘了类型变量名并不重要,您可以重命名它们,只要您以类似方式重命名给定类型变量的所有引用。因此:

(.) map uncurry :: (a -> b1 -> b) -> [(a, b1)] -> [b]
相当于:

(.) map uncurry :: (apple -> pear -> plum) -> [(apple, pear)] -> [plum]
派生类型签名的关键思想:
  • 在开始之前,请确保您的操作员和功能先例正确无误。
    请注意,函数应用程序具有最高优先级,并与左侧关联,因此:
  • 第一个论点是最重要的——先处理它,然后
  • 在类型签名中,
    ->
    关联到右侧
  • 有了第一个参数的类型后,在它出现的任何地方替换该类型
  • 让我们来看看你的例子

    类型

    (.)  :: (b -> c) -> (a -> b) -> a -> c
    map  :: (a -> b) -> [a] -> [b]
    uncurry :: (a -> b -> c) -> (a, b) -> c 
    
    Hugs> :t (.) map
    (map .) :: (a -> b -> c) -> a -> [b] -> [c]
    
    为每个函数指定不重叠的类型名称

    (.)  :: (b -> c) -> (a -> b) -> a -> c
    map  :: (a -> b) -> [a] -> [b]
    uncurry :: (a -> b -> c) -> (a, b) -> c 
    
    Hugs> :t (.) map
    (map .) :: (a -> b -> c) -> a -> [b] -> [c]
    
    首先,这很让人困惑,因为有很多
    a
    s,它们的意思并不完全相同,所以每次我都要用新字母重命名这些类型

    (.)  :: (b -> c) -> (a -> b) -> a -> c
    map  :: (d -> e) -> [d] -> [e]
    uncurry :: (f -> g -> h) -> (f, g) -> h 
    
    将类型括起来,并与右侧关联

    (.)  :: (b -> c) -> ((a -> b) -> a -> c)
    map  :: (d -> e) -> ([d] -> [e])
    uncurry :: (f -> (g -> h)) -> ((f, g) -> h)
    
    将第一个参数的类型与该参数的整个类型匹配 现在让我们看看表达式
    (.)map uncurry
    。正如您现在意识到的,将运算符
    放在括号中会将其转换为遵循正常函数规则的函数,因此
    (.)map uncurry
    表示
    (.)map)uncurry
    ,首先要统一的类型来自
    ()
    map

    现在,
    ()
    有了第一个参数
    (b->c)
    ,因此
    (b->c)
    必须与
    映射的类型统一:

    (.)  :: (   b     ->      c      )   -> ((a -> b) -> (a -> c))
    map  ::  (d -> e) -> ([d] -> [e])
    
    当我们在
    (.)类型中替换
    b~(d->e)
    c~([d]->[e])
    时,我们得到:

    (.) :: ((d->e) -> ([d]->[e]))   ->  ((a -> (d->e)) -> (a -> ([d]->[e])))
    
    因此,
    map
    成为它的第一个参数,所以当我们提供它时,它从类型签名中消失,给出

    (.)           map               ::  ((a -> (d->e)) -> (a -> ([d]->[e])))
    
    与ghci或hugs等口译员核实

    (.)  :: (b -> c) -> (a -> b) -> a -> c
    map  :: (a -> b) -> [a] -> [b]
    uncurry :: (a -> b -> c) -> (a, b) -> c 
    
    Hugs> :t (.) map
    (map .) :: (a -> b -> c) -> a -> [b] -> [c]
    
    是的-当我们添加括号时,由于
    ->
    是右关联的,这些括号是相同的

    转到下一个论点 好的,现在我们有

    (.) map :: ((a -> (d->e)) -> (a -> ([d]->[e])))
    uncurry :: (f -> (g -> h)) -> ((f, g) -> h)
    
    现在很容易匹配这两个第一个参数,因为它们看起来一样,但是我们当然需要将
    (.)map
    的第一个参数与整个
    uncurry
    类型匹配:

    将第一个参数的类型与该参数的整个类型匹配

    (.) map :: ((     a      -> (  d   -> e)) -> (a -> ([d]->[e])))
    uncurry ::   (f->(g->h)) -> ((f,g) -> h)
    
    给出
    a~(f->(g->h))
    d~(f,g)
    e~h

    (.) map :: (((f->(g->h)) -> ((f,g)-> h)) -> ((f->(g->h)) -> ([(f,g)]->[h])))
    
    将其应用于未经批准的

    (.) map            uncurry               :: ((f->(g->h)) -> ([(f,g)]->[h])))
    
    与口译员核对

    Hugs> :t (.) map uncurry
    map . uncurry :: (a -> b -> c) -> [(a,b)] -> [c]
    
    太好了,我们做到了

    与运营商打交道 如果我们以
    length为例。map(.)$repeat id++[]++[]
    ,我们需要所有这些运算符的固定性,但我们可以首先将函数应用程序括起来,因为它们优先:

    length . map (.) $ repeat id ++ [] ++ []
    length . (map (.)) $ (repeat id) ++ [] ++ []
    
    按优先顺序排列运算符

    (.) map :: ((     a      -> (  d   -> e)) -> (a -> ([d]->[e])))
    uncurry ::   (f->(g->h)) -> ((f,g) -> h)
    
    使用解释器的
    :i
    命令查找运算符的固定性,并将它们按顺序排列,最高优先:

    infixr 9 .
    infixr 5 ++
    infixr 0 $
    
    优先级最高的运算符
    首先被括起来:

    (length . (map (.))) $ (repeat id) ++ [] ++ []
    
    然后,
    ++
    ,它与右侧关联:

    (length . (map (.))) $ ((repeat id) ++ ([] ++ []))
    
    而且
    $
    只有一个用法,所以我没有费心把它括起来

    如果愿意,可以将
    ++
    之类的运算符转换为函数
    (++)
    ,但我完全不相信这会对您有所帮助,所以我就不谈了,只要记住第一个参数在左边

    从最嵌套的括号开始通常会有所帮助。

    在派生类型签名时:
  • 在开始之前,请确保您的操作员和功能先例正确无误。
    请注意,函数应用程序具有最高优先级a