功能组成类型

时间:2014-10-30 19:57:56

标签: haskell

我很难理解功能组合类型的结果,例如

ghci> :t (id . const)
(id . const) :: a -> b -> a
ghci> :t ((:) . (+))
((:) . (+))  :: a -> [a -> a] -> [a -> a]

你们通常如何得出函数组合类型?

3 个答案:

答案 0 :(得分:2)

这很简单,最初写下两个函数的类型:

> :t const
const :: a -> b -> a
> :t id
id :: a -> a

(id . const)被翻译为\x -> id (const x)

(const x)          :: b -> a      -- (Note that the type of `x` is `a` here)
id (const x)       :: b -> a      -- The output of id type will be the same as the input it takes
\x -> id (const x) :: a -> b -> a -- We aleady know the type of x

您可以按照相同的步骤进行下一个功能。

答案 1 :(得分:1)

让我们看看

> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c

总的来说:

  1. 给出两个功能。将它们视为一个参数的curried函数,即类型函数 a -> b -> c -> ... -> z我们将其视为一个参数的函数a -> ( b -> c -> ... -> z ),它返回一个参数较少的函数。
  2. 第二功能的结果类型应与第一功能的参数类型相同。因此将第一函数的参数作为第二个结果参数。将其表示为 b
  3. 整个组合的结果类型应该等于第二个函数的参数类型(表示为 a )到第一个函数的结果类型的函数(将其表示为 { {1}}
  4. c

    > :t (id . const)

    将其重命名为> :t id id :: a -> a

    x -> x

    请注意,> :t const const :: a -> b -> a 此处不一定与之前的类型等式相同,有些将其重命名为a

    y -> z -> y

    因此结果a = y b = z -> y = x c = x = z -> y a -> c = y -> ( z -> y)相同 总体语义等于a -> b -> c

    const

    > :t ((:) . (+))

    将其重命名为> :t (:) (:) :: a -> [a] -> [a]

    x -> [x] -> [x]

    将其重命名为> :t (+) (+) :: Num a => a -> a -> a

    Num y => y -> y -> y

    我们也有类型类a = y b = y -> y = x c = [x] -> [x] = [y -> y] -> [y -> y] 的限制 因此总体类型Num yNum y => a -> c = y -> [y -> y] -> [y -> y]相同 整体语义是"制作单个参数函数,将第一个参数添加到数值,并将该函数预先添加到给定的单个参数函数列表中#34;

答案 2 :(得分:1)

练习:手动查找下面的函数合成类型,而不是使用GHCi。做这些练习来建立关于函数类型推理的直觉。请记住a -> a类型,其中a是一个类型变量,不仅匹配Int -> Int[Bool] -> [Bool],还匹配(a -> a) -> (a -> a)。如果您无法进行练习,请阅读以下内容。

  1. (*3) . (+2)(简单)
  2. (*) . (+2)
  3. (:) . (+2)
  4. (:) . (*)
  5. 什么是function?这是一个需要输入并返回输出的东西。不仅是随机输出,还取决于输入的输出。对于相同的输入,相同的功能始终返回相同的输出。一个函数将一些东西转换为另一个东西。输入和输出可以是不同的types。所以想象一个函数是一个神奇的单向管:你把一个东西放在标有 in 的洞中,从另一个名为 out 的洞中得到一些东西,可能是完全不同的形式。就像,你把西红柿放在一个管子里,从另一端拿一把机关枪。但请记住,功能是单向的,你不能在功能的 out 孔中放置任何东西。

    a :: Int -> Int -- take a thing of type Int and return a thing of type Int
    a n = n + 2
    
    b :: Int -> Int 
    b n = n -- a function can even return the same value
    
    c :: Int -> Bool -- an output can be of different type than input
    c n = n `mod` 3 == 0
    

    Haskell支持higher-order functions,默认为curried。这意味着Haskell中没有多参数函数,每个函数只接受1个参数,但有时它们可​​以返回函数。 Haskell管总是只有一个孔 ,但有时管子从孔中弹出管 out !甚至有管子,你可以放其他管子。函数类型是右关联的,这意味着a -> b -> ca -> (b -> c) 是同一件事

    :t (+) -- Num a => a -> a -> a
    :t (:) -- a -> [a] -> [a]
    

    那么function composition是什么?当你将功能组合成一个新功能,或者将两个管子熔合在一起时,将1 st < strong> out 焊接到2 nd in ,这样无论你放入第一根管子的孔中,它都会从第二根管中掉出来并弹出#39; s out 洞。

    然后可以将组合功能想象为由两个焊接在一起的较短管制成的长管。组合函数的类型是什么?我们的新管仍有2个孔,一个标记为 ,另一个标记为 out 。但请记住,我们的新管中的 对应于第一部分的 ,而我们新管的 out 对应 out < / strong>第二部分。因此,类型将从输入到1 st 函数的任何内容输出到2 nd 函数的输出。

    :t (:[2,3]) . (+1) -- Num a => a -> [a]
    -- why?
    :t (+1)     -- Num a => a -> a
    :t (:[2,3]) -- Num a =>      a -> [a]
    

    我们将2个函数连接在一起,第一个输出到第二个输入,并获得一个仍然有一个输入和一个输出的新函数。这正是函数运算符的类型所说的:

    :t (.) -- (b -> c) -> (a -> b) -> (a -> c)
    

    由于历史事故,函数组成从右向左,因此(*3) . (+2)是一个函数,首先将2加到一个数字,然后将结果乘以3。那么如何演绎一种功能组合呢?你将2 nd 函数的输入与1 st 函数的输出联系起来,并抛弃它们之间的类型。

    a -> b
         b -> c   becomes
    a    ->   c
    

    另请参阅: [1][2][3][4],了解有关如何使用函数组合以及如何推理的更多信息功能类型。