Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/visual-studio-code/3.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:使用两个浮动参数组合函数失败_Haskell_Function Composition - Fatal编程技术网

Haskell:使用两个浮动参数组合函数失败

Haskell:使用两个浮动参数组合函数失败,haskell,function-composition,Haskell,Function Composition,我试图将(浮动a)=>a->a->a类型的函数与(浮动a)=>a->a类型的函数组合,以获得(浮动a)=>a->a类型的函数。我有以下代码: test1 :: (Floating a) => a -> a -> a test1 x y = x test2 :: (Floating a) => a -> a test2 x = x testBoth :: (Floating a) => a -> a -> a testBoth = test2 .

我试图将
(浮动a)=>a->a->a
类型的函数与
(浮动a)=>a->a
类型的函数组合,以获得
(浮动a)=>a->a
类型的函数。我有以下代码:

test1 :: (Floating a) => a -> a -> a
test1 x y = x

test2 :: (Floating a) => a -> a
test2 x = x

testBoth :: (Floating a) => a -> a -> a
testBoth = test2 . test1
--testBoth x y = test2 (test1 x y)
但是,当我在GHCI中编译它时,我得到以下错误:

/path/test.hs:8:11:
    Could not deduce (Floating (a -> a)) from the context (Floating a)
      arising from a use of `test2'
                   at /path/test.hs:8:11-15
    Possible fix:
      add (Floating (a -> a)) to the context of
        the type signature for `testBoth'
      or add an instance declaration for (Floating (a -> a))
    In the first argument of `(.)', namely `test2'
    In the expression: test2 . test1
    In the definition of `testBoth': testBoth = test2 . test1
Failed, modules loaded: none.
请注意,注释掉的
testBoth
版本可以编译。奇怪的是,如果我从所有类型签名中删除
(浮动a)
约束,或者如果我将
test1
更改为只取
x
,而不是
x
y
testBoth
编译

我搜索了StackOverflow、Haskell wikis、Google等,没有发现任何与此特定情况相关的函数组合限制。有人知道为什么会这样吗

   \x y -> test2 (test1 x y)
== \x y -> test2 ((test1 x) y)
== \x y -> (test2 . (test1 x)) y
== \x -> test2 . (test1 x)
== \x -> (test2 .) (test1 x)
== \x -> ((test2 .) . test1) x
== (test2 .) . test1
这两样东西不一样

   test2 . test1
== \x -> (test2 . test1) x
== \x -> test2 (test1 x)
== \x y -> (test2 (test1 x)) y
== \x y -> test2 (test1 x) y

您的问题与浮动无关,尽管typeclass确实使您的错误更难理解。以下面的代码为例:

test1 :: Int -> Char -> Int
test1 = undefined

test2 :: Int -> Int
test2 x = undefined

testBoth = test2 . test1
这两种测试的类型是什么?好的,我们采用
(::(b->c)->(a->b)->a->c的类型,转动曲柄得到:

  • b~Int
    (test2的参数与
    ()
    的第一个参数统一)
  • c~Int
    (test2
  • 的结果与
    (.
    )的第一个参数的结果统一)
  • a~Int
    test1
    参数1与
    (.)的参数2统一)
  • b~Char->Int
    (测试1的结果与
    ()
    的参数2统一)
  • 但是等等!该类型变量“b”(#4,
    Char->Int
    )必须与
    test2
    (#1,
    Int
    )的参数类型统一。哦,不

    你应该怎么做?正确的解决方案是:

    testBoth x = test2 . test1 x
    
    有其他的方法,但我认为这是最可读的。< /P>
    编辑:那么,试图告诉你的错误是什么?有人说,将
    浮动a=>a->a
    浮动b=>b
    统一需要
    实例浮动(a->a)
    。。。虽然这是真的,但您确实不希望GHC尝试将函数视为浮点数。

    您的问题与
    浮点数无关,而是您希望以不进行类型检查的方式组合一个具有两个参数的函数和一个具有一个参数的函数。我将给出一个组合函数<代码>反转的例子。foldr(:)[]

    相反。foldr(:)[]
    的类型为
    [a]->[a]
    并按预期工作:它返回一个反向列表(
    foldr(:)[]
    基本上用于列表)

    然而,
    相反。foldr(:)
    不进行类型检查。为什么?

    当类型与函数组合匹配时 让我们回顾一些类型:

    reverse      :: [a] -> [a]
    foldr (:)    :: [a] -> [a] -> [a]
    foldr (:) [] :: [a] -> [a]
    (.)          :: (b -> c) -> (a -> b) -> a -> c
    
    相反。foldr(:)[]
    类型检查,因为
    ()
    实例化为:

    (.) :: ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
    
    换句话说,在
    ()
    的类型注释中:

    • a
      变成
      [a]
    • b
      变成
      [a]
    • c
      变成
      [a]
    所以<代码>相反。foldr(:)[]
    的类型为
    [a]->[a]

    当类型与函数组合不匹配时
    相反。foldr(:)
    不进行类型检查,因为:

    foldr (:) :: [a] -> [a] -> [a]
    
    作为
    ()
    的正确操作符,它将把它的类型从
    a->b
    实例化为
    [a]->([a]->[a])
    。即:

    (b -> c) -> (a -> b) -> a -> c
    
    • 类型变量
      a
      将替换为
      [a]
    • 类型变量
      b
      将替换为
      [a]->[a]
    如果
    foldr(:)
    的类型为
    a->b
    ,则
    (.foldr(:)
    的类型为:

    (b -> c) -> a -> c`
    
    foldr(:)
    作为右操作符应用于
    ()

    但是因为
    foldr(:)
    的类型是
    [a]->([a]->[a])
    ,所以
    (.foldr(:)
    的类型是:

    (([a] -> [a]) -> c) -> [a] -> c
    
    相反。foldr(:)
    不进行类型检查,因为
    reverse
    的类型是
    [a]->[a]
    ,而不是
    ([a]->[a])->c

    猫头鹰操作员 当人们第一次在Haskell中学习函数组合时,他们了解到当函数的最后一个参数位于函数体的最右边时,可以从参数和函数体中删除它,用点替换括号(或美元符号)。换句话说,以下4个函数定义是等效的:

    f a x xs = g . h a . i x $ xs
    f a x xs = g . h a . i $ x xs
    
    所以人们有一种直觉说“我只是从主体和参数中移除最右边的局部变量”,但这种直觉是错误的,因为一旦你移除了
    xs

    f a x = g . h a . i x
    f a   = g . h a . i
    
    他们不是对等的!您应该了解函数组合类型何时检查,何时不检查。如果上述2项是等效的,则意味着以下2项也是等效的:

    f a x xs = g . h a . i x $ xs
    f a x xs = g . h a . i $ x xs
    
    这毫无意义,因为
    x
    不是一个以
    xs
    作为参数的函数
    x
    是函数
    i
    的参数,
    xs
    是函数
    (ix)
    的参数

    有一个技巧可以使一个具有两个参数的函数无点。也就是说,使用“owl”操作符:

    f a x xs = g . h a .  i x xs
    f a      = g . h a .: i
      where (.:) = (.).(.)
    
    上述两个函数定义是等效的。阅读

    工具书类 一旦您了解了函数、类型、部分应用程序和货币化、函数组合和美元运算符,Haskell编程就变得简单明了了。要明确这些概念,请阅读以下答案:

    另请阅读:


    谢谢。简洁明了。我以前没有见过(test2.)符号,但它的意思一定是f |->