我很难理解功能组合类型的结果,例如
ghci> :t (id . const)
(id . const) :: a -> b -> a
ghci> :t ((:) . (+))
((:) . (+)) :: a -> [a -> a] -> [a -> a]
你们通常如何得出函数组合类型?
答案 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
总的来说:
a -> b -> c -> ... -> z
我们将其视为一个参数的函数a -> ( b -> c -> ... -> z )
,它返回一个参数较少的函数。b
。a
)到第一个函数的结果类型的函数(将其表示为 { {1}} 强>)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 y
与Num y => a -> c = y -> [y -> y] -> [y -> y]
相同
整体语义是"制作单个参数函数,将第一个参数添加到数值,并将该函数预先添加到给定的单个参数函数列表中#34;
答案 2 :(得分:1)
练习:手动查找下面的函数合成类型,而不是使用GHCi。做这些练习来建立关于函数类型推理的直觉。请记住a -> a
类型,其中a
是一个类型变量,不仅匹配Int -> Int
或[Bool] -> [Bool]
,还匹配(a -> a) -> (a -> a)
。如果您无法进行练习,请阅读以下内容。
(*3) . (+2)
(简单)(*) . (+2)
(:) . (+2)
(:) . (*)
什么是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 -> c
和a -> (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