Haskell中的const函数

时间:2012-01-30 10:12:34

标签: haskell

函数const在Prelude中定义为:

const x _ = x

在GHCi中,当我尝试

Prelude> const 6 5  -> Gives 6

但是当我尝试

Prelude> const id 6 5 -> Gives 5

即使在进行了像

这样的更改之后
Prelude> (const id 6) 5 -> Gives 5

此函数不应该给6,因为函数id的输出具有应该绑定的类型id :: a -> a

Prelude> (const 6) 5 -> Gives 6

为什么函数const的行为有所不同?

3 个答案:

答案 0 :(得分:63)

您似乎认为这相当于const (id 6) 5,其中id 6的计算结果为6,但事实并非如此。如果没有这些括号,您将id函数作为第一个参数传递给const。请再次查看const的定义:

const x _ = x

这意味着const id 6 = id。因此,const id 6 5相当于id 5,实际上是5。

答案 1 :(得分:14)

函数也可以是其他函数的参数。 id 成为 const 的参数。

(const id 6)5 的表达方式实际上是:

  

(const id 6)5

     

(const id _)5 - 抓住第一个参数 id

     

id 5

     

5

有关运营商真正做的更多细节:

  1. 一对括号中的任何内容都将被视为整个表达式(但并不意味着它将首先计算)。例如:(地图(1 +))(\ x - >( - )x)

  2. 前缀运算符绑定比中缀运算符更强

  3. 表达式中最左边的前缀运算符将被视为一个函数,它从左到右抓取表达式中的参数(包括其他前缀运算符),直到面向中缀运算符或行尾。例如,如果您在GHCi中键入 map(+)id 3 const + 2 ,您将收到一条错误,上面写着“函数`map'应用于四个参数......”因为地图在中缀运算符之前抓取(+) id 3 const 作为参数的 +

答案 2 :(得分:5)

Chuck is right,Haskell中的函数应用程序是left associative,这意味着像f a b c这样的函数调用等同于(((f a) b) c)。请记住,在Haskell中,您应该始终练习查看函数类型,并尝试根据函数类型推断函数可以做什么和不可以做什么。起初你可能无法从函数类型中推断出任何东西,但是有了更多经验,类型信息将变得不可或缺。

const的类型是什么?在GHCi中输入:t const。它将返回const :: a -> b -> aabtype variables,这意味着const将接受任何类型的参数。由于1 st 和2 nd 参数具有不同的类型,您几乎可以将所有内容传递给函数:

const 1 2 -- returns 1
const 'a' 1 -- returns 'a'
const [1,2,3] "a" -- returns [1,2,3]

const的类型变量可能存在特定的typeclass constraints会阻止传递函数,例如NumOrd,因为函数不是实例这些类型。换句话说,函数不会表现为数字或有序事物,因此f + gf < g没有意义。但是const没有类型类约束阻止我们将函数作为参数传递。请记住,Haskell支持higher-order functions?这意味着Haskell的函数可以接受并返回其他函数。因此:

const (+) (*) -- returns (+)
const head tail -- returns head
const id 2 -- returns id

const只是忽略2 nd 参数并返回作为1 st 参数传递的任何内容,无论是Char,String,Integer,Maybe, [],一些非常复杂的代数数据类型,甚至是函数。

如果const的类型为a -> b -> a,您是否可以在没有在GHCi中输入const 'a'的情况下找出:t const 'a'而没有找到它的类型?要找出const 'a'的类型,用1 st 参数的类型代替所有相同的类型变量,然后从类型中删除第一个参数。

  1. a -> b -> a:原始类型
  2. Char -> b -> Char:在类型变量a
  3. 中替换新类型
  4. b -> Char:通过从类型声明中删除第一个参数的新函数的类型
  5. 那么const id的类型是什么?

    1. a -> b -> a:原始类型
    2. (a -> a) -> b -> (a -> a):替换
    3. b -> (a -> a):结果类型(删除第一个参数)
    4. b -> a -> a:与上述相同,->运算符为right-associative
    5. <强>练习:

      1. 尝试在不使用GHCi的情况下精神上或使用笔和纸来计算,有哪些类型:const (+)const headconst tailconst (++),{{ 1}}
      2. 尝试找出哪些参数将传递给上述函数以获得具体值。