本文介绍了哈斯克尔怪异的表达的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! Prelude>我想了解为什么以下是Haskell中的有效表达式:让e =(+)( - ) Prelude> :type e e ::(Num(a - > a - > a),Num a)=> (a - > a - > a) - > a - > a - > a 更奇怪的是,表单中的任何表达式 e 1 2 3 4 ... N 无论N都是难以理解的类型的有效表达式。例如, Prelude> :te 1 2 3 4 5 e 1 2 3 4 5 ::(Num((a→a1→t)→a→a1→t) a→a→t), Num(a→a1→t),Num a1,Num a)=> t 这是咖啡和类型推断的不幸后果吗? 欢迎澄清。 解决方案这不是一个不幸的后果。实际上,有些人可能会将其视为一项功能! (+)和( - )的类型为 > :t(+)(+):: Num a => a - > a - > a > :t( - )( - ):: Num a => a - > a - > a 认识到 类型 a ,即使 a 是一个函数类型。因此,例如,如果类型 b - > b - > b 有一个 Num 实例,那么您可以将(+)限制为 (+):: Num(b - > b - > b)=> (b - > b - > b) - > (b - > b - > b) - > b - > b - > b 只需设定 a = b - > b - > B'/ code>。由于currying,最后三个 b s中的括号是不必要的(你可以写入它们,但它们会是多余的)。 现在, Num b => b - > b - > b 恰恰是( - )的类型(前提条件是 b 本身具有有一个 Num 实例),所以函数( - )填充(+)和(+)( - )的类型是 b - > b) - > b - > b - > b 这就是您观察到的情况。 这就提出了为什么实际上对函数有一个 Num 实例可能是有用的问题。事实上,为函数定义一个 Num 实例是否有意义?我声称它的确如此!你可以定义 instance Num a => Num(r→a)其中,(f + g)r = fr + gr (f-g)r = fr -gr (f * g)r = fr * gr abs fr = abs(fr) signum fr = signum(fr) fromInteger nr = fromInteger n 这非常适合作为 Num 实例。事实上,这正是您需要解释表达式的实例 e - >让e =(+)( - )> e 3 2 1 4 Buh?!? 发生了以下事情。由于(Num a)=> r - >一个是任何 r 的有效 Num 实例,您可以将 r with a - >一个,它表明(Num a)=> a - > a - >一个也是一个有效的 Num 实例。所以你有 - 请记住(+)f = \g r - > fr + gr (+)( - )3 2 1 =(\ grs - >( - )rs + grs)3 2 1 - 函数 =(\ rs - >( - )rs + 3 rs)2 1 - beta缩减 =(\ s - >( - )2 s + 3 2 s)1 - β减少 =( - )2 1 + 3 2 1 - β减少 =(2-1)+ 3 - 因为(3 2)= 3和(3 1)= 3有一点令人费解(特别是,有些人认为,请确保你理解为什么 3 2 = 3 ),但是一旦你扩展了所有的定义,不要太混淆! 您要求派生Haskell使用的(+)( - )类型。它依赖于类型变量的统一。它就像这样 - 您知道(+):: Num a => a - > a - > a 和( - ):: Num b => b - > b - > b (我使用不同的字母,因为我们希望将它们混合在一起) 如果要将( - )放入(+)的第一个槽中,您必须具有 a〜b - > b - > b ,所以组合的类型是 (+)( - )::(Num a,Num b,a〜b - > b - > b)=> (b - > b - > b) - > (b - > b - > b) 现在,您将 a code> b - > b - > b (如胖箭头左边所示,由〜标志),让您留下 b - > b) - > (b - > b - > b) 如果我们删除最右括号(因为它们是多余的)并将 b 到 a ,这是Haskell推断的类型签名。 I would like to understand why the following is a valid expression in Haskell:Prelude> let e = (+) (-)Prelude> :type ee :: (Num (a -> a -> a), Num a) => (a -> a -> a) -> a -> a -> aMore strange is that any expression in the forme 1 2 3 4 ... Nwhatever N are all valid expressions of uncomprehensible type. For example,Prelude> :t e 1 2 3 4 5e 1 2 3 4 5 :: (Num ((a -> a1 -> t) -> (a -> a1 -> t) -> a -> a1 -> t), Num (a -> a1 -> t), Num a1, Num a) => tIs this an unfortunate consequence of currying and type inference?Clarifications are welcome. 解决方案 It's not an "unfortunate consequence". In fact, some might see it as a feature! The types of (+) and (-) are> :t (+)(+) :: Num a => a -> a -> a> :t (-)(-) :: Num a => a -> a -> aIt's important to realize that this is valid for any type a, even if a is a function type. So, for example, if the type b -> b -> b has a Num instance, then you could restrict (+) to(+) :: Num (b -> b -> b) => (b -> b -> b) -> (b -> b -> b) -> b -> b -> bby simply setting a = b -> b -> b. Because of currying, the parentheses around the last three bs are unnecessary (you could write them in but they would be redundant).Now, Num b => b -> b -> b is exactly the type of (-) (with the proviso that b itself has to have a Num instance), so the function (-) fills the first "slot" of (+) and the type of (+) (-) is(+) (-) :: (Num b, Num (b -> b -> b)) -> (b -> b -> b) -> b -> b -> bwhich is what you observed.This raises the question of why on earth it might be useful to have a Num instance for functions at all. In fact, does it even make sense to define a Num instance for functions?I claim that it does! You can defineinstance Num a => Num (r -> a) where (f + g) r = f r + g r (f - g) r = f r - g r (f * g) r = f r * g r abs f r = abs (f r) signum f r = signum (f r) fromInteger n r = fromInteger nwhich makes perfect sense as a Num instance. And in fact, this is precisely the instance you need to interpret your expression e -> let e = (+) (-)> e 3 2 14Buh?!?What happened is the following. Since (Num a) => r -> a is a valid Num instance for any r, you can replace r with a -> a, which shows that (Num a) => a -> a -> a is also a valid Num instance. So you have-- Remember that (+) f = \g r -> f r + g r (+) (-) 3 2 1= (\g r s -> (-) r s + g r s) 3 2 1 -- definition of (+) on functions= (\ r s -> (-) r s + 3 r s) 2 1 -- beta reduction= (\ s -> (-) 2 s + 3 2 s) 1 -- beta reduction= (-) 2 1 + 3 2 1 -- beta reduction= (2 - 1) + 3 -- since (3 2) = 3 and (3 1) = 3= 1 + 3= 4A little convoluted (in particular, make sure you understand why 3 2 = 3) but not too confusing once you've expanded all the definitions out!You asked for the derivation of the type of (+) (-) that Haskell uses. It relies on the idea of "unification" of type variables. It goes something like this -You know that (+) :: Num a => a -> a -> a and (-) :: Num b => b -> b -> b (I use different letters because we will want to mash these together).If you are going to put (-) into the first slot of (+) you must have a ~ b -> b -> b, so the combined type is(+) (-) :: (Num a, Num b, a ~ b -> b -> b) => (b -> b -> b) -> (b -> b -> b)Now you "unify" a with b -> b -> b (as indicated on the left of the fat arrow, by the ~ sign) which leaves you with(+) (-) :: (Num (b -> b -> b), Num b) => (b -> b -> b) -> (b -> b -> b)If we remove the right-most parentheses (because they are redundant) and rename b to a, this is the type signature that Haskell infers. 这篇关于哈斯克尔怪异的表达的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!