我在理解haskell中的类型方面遇到了一些困难。让我们考虑以下函数并查看它们的类型。
reduce f s [] = s
reduce f s (x:xs) = f x (reduce f s xs)
for m n f s = if m>n then s else for (m+1) n f ( f m s )
comp f g x y = f x (g x y)
iter 0 f s = s
iter n f s = iter (n-1) f (f s)
我们有类似的东西:
reduce :: (t1 -> t -> t) -> t -> [t1] -> t
for :: (Ord a, Num a) => a -> a -> (a -> t -> t) -> t -> t
comp :: (t -> t2 -> t3) -> (t -> t1 -> t2) -> t -> t1 -> t3
iter :: (Num t) => t -> (t1 -> t1) -> t1 -> t1
我不清楚的是,在reduce函数中f取两个参数,而for f函数再取两个参数。我只能看到它只需要一个。好吧,如果它会是这样的:
for m n f s = if m>n then s else for (m+1) n f m n
更明显也很容易认识到f确实需要两个参数。
我想知道是否存在一些方法或方法来推断haskell中函数的类型。除了这些例子之外,我还要求提供一些不同的例子,这样我才能克服困难。
编辑:在我的情况下给出了函数定义,我只是想推断它们的类型
答案 0 :(得分:6)
即使考虑f ( f m s )
,你在思考错误的地方也是如此。那是不 for
定义的子表达式:回想一下,函数应用程序是从左边解析的。所以
for (m+1) n f ( f m s )
≡ (for (m+1)) n f ( f m s )
≡ (for (m+1) n) f ( f m s )
≡ (for (m+1) n f) ( f m s )
≇ (for (m+1) n ) (f ( f m s ))
≇ for (m+1) (n f ( f m s ))
≇ for ((m+1) n f ( f m s ))
最后的不平等可能是最明显的,因为你将函数(m+1)
应用于三个参数......这看起来确实不太可能。
如果您需要任何"精神上的括号"为了理解函数,通常最好将它们放在每个函数参数周围:
for (m+1) n f ( f m s )
≡ for (m+1)
(n)
(f)
(f m s)
并且,如果这对您有所帮助,因为它看起来更像您在主流语言中的含义,那么您也可以取消所有内容:
≅ for ( m+1, n, f, f(m,s) )
(尽管你最好快点忘掉那个)
顺便说一句:如果你看到一个函数只应用于一个参数,那么它并不意味着函数类型只有 一个参数。事实上,Haskell的语法的主要优势在于你可以轻松地进行部分应用:例如。
前奏> :t取
take :: Int - > [a] - >并[a]
前奏> :t取3
取3 :: [a] - >并[a]
前奏>地图(拍3)[" looooong","甚至更长","非常长"]
["厕所""前夕""叔"]
您发现我只将take
应用于一个参数,另一个参数会自map
从列表中删除。
另一个例子,有操作符部分,
前奏> :t(+)
(+):: Num a => a - > a - >一个
前奏> :t(+ 1)
(+ 1):: Num a => a - >一个
前奏>地图(+ 1)[4,5,6]
[5,6,7]
答案 1 :(得分:1)
以下定义中f
的类型很容易推断
for m n f s = if m>n then s else for (m+1) n f ( f m s )
这可以改写为(清晰)
for m n f s
| m>n = s
| otherwise = for (m+1) n f ( f m s )
for (m+1) n f (f m s)
是for
,
表示f m s
需要与s
具有相同的类型,
这需要f
具有t1 -> t -> t
类型
(t1
为m
,t
为s