gpt4 book ai didi

haskell - 数字作为乘法函数(奇怪但有趣)

转载 作者:行者123 更新时间:2023-12-03 14:03:19 24 4
gpt4 key购买 nike

在问题的评论Tacit function composition in Haskell ,人们提到制作 Num a -> r 的实例,所以我想我会使用函数符号来表示乘法:

{-# LANGUAGE TypeFamilies #-}
import Control.Applicative

instance Show (a->r) where -- not needed in recent GHC versions
show f = " a function "

instance Eq (a->r) where -- not needed in recent GHC versions
f == g = error "sorry, Haskell, I lied, I can't really compare functions for equality"

instance (Num r,a~r) => Num (a -> r) where
(+) = liftA2 (+)
(-) = liftA2 (-)
(*) = liftA2 (*)
abs = liftA abs
negate = liftA negate
signum = liftA signum
fromInteger a = (fromInteger a *)

注意 fromInteger 定义意味着我可以写 3 4计算结果为 12 和 7 (2+8)是 70 岁,正如你所希望的那样。

然后一切都变得奇妙,有趣而奇怪!如果可以的话,请解释这种奇怪:
*Main> 1 2 3
18
*Main> 1 2 4
32
*Main> 1 2 5
50
*Main> 2 2 3
36
*Main> 2 2 4
64
*Main> 2 2 5
100
*Main> (2 3) (5 2)
600

[编辑:使用 Applicative 而不是 Monad,因为 Applicative 通常很棒,但它对代码没有太大影响。]

最佳答案

在像 2 3 4 这样的表达式中对于您的实例,23是函数。所以2实际上是 (2 *)并且有一个类型 Num a => a -> a . 3是一样的。 2 3然后是 (2 *) (3 *)2 * (3 *) 相同.根据您的情况,这是 liftM2 (*) 2 (3 *)然后是 liftM2 (*) (2 *) (3 *) .现在这个表达式可以在没有任何实例的情况下工作。

那么这是什么意思?好吧,liftM2 for 函数是一种双重组合。特别是,liftM2 f g h\ x -> f (g x) (h x) 相同.所以liftM2 (*) (2 *) (3 *)然后是 \ x -> (*) ((2 *) x) ((3 *) x) .稍微简化一下,我们得到:\ x -> (2 * x) * (3 * x) .所以现在我们知道 2 3 4实际上是 (2 * 4) * (3 * 4) .

那么,为什么 liftM2函数以这种方式工作?让我们看看 (->) r 的 monad 实例(请记住 (->) r(r ->) 但我们不能编写类型级运算符部分):

instance Monad ((->) r) where  
return x = \_ -> x
h >>= f = \w -> f (h w) w

所以 returnconst . >>=有点奇怪。我认为从 join 的角度来看更容易理解。 .对于函数, join像这样工作:
join f = \ x -> f x x

也就是说,它采用两个参数的函数,并通过使用该参数两次将其转换为一个参数的函数。很简单。这个定义也是有道理的。对于函数, join必须将两个参数的函数变成一个函数;唯一合理的方法是使用该参数两次。
>>=fmap后跟 join .对于函数, fmap只是 (.) .所以现在 >>=等于:
h >>= f = join (f . h)

这只是:
h >>= f = \ x -> (f . h) x x

现在我们只需摆脱 .要得到:
h >>= f = \ x -> f (h x) x

所以现在我们知道了 >>=作品,我们可以看看 liftM2 . liftM2定义如下:
liftM2 f a b = a >>= \ a' -> b >>= \ b' -> return (f a' b')

我们可以简单的一点一点。一、 return (f a' b')变成 \ _ -> f a' b' .结合 \ b' -> ,我们得到: \ b' _ -> f a' b' .然后 b >>= \ b' _ -> f a' b'变成:
 \ x -> (\ b' _ -> f a' b') (b x) x

自第二个 x被忽略,我们得到: \ x -> (\ b' -> f a' b') (b x)然后减少到 \ x -> f a' (b x) .所以这给我们留下了:
a >>= \ a' -> \ x -> f a' (b x)

再次,我们替换 >>= :
\ y -> (\ a' x -> f a' (b x)) (a y) y

这减少到:
 \ y -> f (a y) (b y)

这正是我们使用的 liftM2早点!

希望现在 2 3 4 的行为完全有道理。

关于haskell - 数字作为乘法函数(奇怪但有趣),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12133932/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com