% 在 Haskell 中有什么作用?
What does % do in Haskell?
我习惯用 % 在其他语言中表示 "modulo"。在Haskell中,我们必须使用mod x y
或x `mod` y
。那么,这个符号在Haskell中有什么用呢?
Searching for (%)
on Stackage Hoogle,似乎 Data.Ratio
将 %
运算符定义为从分子和分母构造 Ratio
值。 GHCi 示例:
Prelude> :m + Data.Ratio
Prelude Data.Ratio> let x = 1 % 2
Prelude Data.Ratio> x
1 % 2
Prelude Data.Ratio> :t x
x :: Integral a => Ratio a
快速查看 Hoogle,您可以看到 %
是一个定义为
的中缀函数
(%) :: Integral a => a -> a -> Ratio a
您可以猜到它是 Data.Ratio
库的一部分,该库主要处理比率(即:分数)。它的代码是
x % y = reduce (x * signum y) (abs y)
因此给定两个积分 (x,y) ,它 returns 一个不可约分数 x/y
在Haskell中,我们可以像普通函数一样定义各种符号(包括%
)的二元运算符,所以你可以将%
定义为你想要的任意运算符(在你定义它的模块)。
作为最典型的例子,%
被Data.Ratio module作为Ratio
类型的构造函数提供。
在 GHCi 上尝试以下代码以确保 %
由 Data.Ratio
提供:
ghci> 3 % 9
<interactive>:1:3: error:
Variable not in scope: (%) :: Integer -> Integer -> t
ghci> import Data.Ratio
ghci> 3 % 9
1 % 3
请记住,您可以在这些搜索引擎中搜索此类运算符和函数:
其实我查过 %
是如何被 Hoogle 定义的。
% 是定义为
的中缀函数
(%) :: Integral a => a -> a -> Ratio a
并且从上面的类型定义中,您可以看到它是 Data.Ratio
库的一部分,该库主要处理比率(即:分数)。它的代码是
x % y = reduce (x * signum y) (abs y)
因此给定两个积分 (x,y) ,它 returns 一个不可约分数 x/y
Data.Ratio
使用 %
作为构造函数,但除非该类型是在 Integral
类型 class 之前定义的,否则它无法解释为什么 %
可用 供 Data.Ratio
使用。 (当然,合格的导入允许您在多个模块中使用相同的运算符名称,所以无论哪种方式,%
被 Data.Ratio
使用都不是真正的理由。)
但是请注意,Integral
定义了 both mod
and rem
functions。我怀疑 %
被故意排除在 Integral
之外,都是为了避免 1) 选择它是否应该是 mod
或 rem
的别名,以及as 2) 让人们记住做出的选择。
另外,languages use different definitions for %
,所以 (%) = mod
或 (%) = rem
都有可能混淆 某人 。
在“老派”戴维斯 Introduction to Functional Programming Systems Using Haskell 中找到此内容。 (他经常拿Haskell比作Pascal。)这是对栈运算的模拟
type Stack = [Float]
push :: Float -> Stack -> Stack
push x stack = x : stack
addStack :: Stack -> Stack
addStack (x:y:stack) = (y + x) : stack
subtStack :: Stack -> Stack
subtStack (x:y:stack) = (y - x) : stack
multStack :: Stack -> Stack
multStack (x:y:stack) = (y * x) : stack
divStack :: Stack -> Stack
divStack (x:y:stack) = (y / x) : stack
emptyStack :: Stack
emptyStack = []
popStack :: Stack -> (Float, Stack)
popStack (top:rest) = (top,rest)
然后
let f % g = g . f
actionsOn = push 12.2 %
push 7.1 %
push 6.7 %
divStack %
push 4.3 %
subtStack %
multStack %
push 2.2 %
addStack
in popStack (actionsOn emptyStack)
(-37.331642,[])
这只是看起来很疯狂的嵌套函数的简洁版本
popStack (addStack (push 2.2 (multStack (subtStack (push 4.3 (divStack (push 6.7 (push 7.1 (push 12.2 emptyStack)))))))))
它本身避免为每个堆栈操作创建和传递新堆栈。总而言之,YAMAMOTO Yuji 一开始所说的适用于此,而不是任何 Ratio
东西 AFAIK。
我习惯用 % 在其他语言中表示 "modulo"。在Haskell中,我们必须使用mod x y
或x `mod` y
。那么,这个符号在Haskell中有什么用呢?
Searching for (%)
on Stackage Hoogle,似乎 Data.Ratio
将 %
运算符定义为从分子和分母构造 Ratio
值。 GHCi 示例:
Prelude> :m + Data.Ratio
Prelude Data.Ratio> let x = 1 % 2
Prelude Data.Ratio> x
1 % 2
Prelude Data.Ratio> :t x
x :: Integral a => Ratio a
快速查看 Hoogle,您可以看到 %
是一个定义为
(%) :: Integral a => a -> a -> Ratio a
您可以猜到它是 Data.Ratio
库的一部分,该库主要处理比率(即:分数)。它的代码是
x % y = reduce (x * signum y) (abs y)
因此给定两个积分 (x,y) ,它 returns 一个不可约分数 x/y
在Haskell中,我们可以像普通函数一样定义各种符号(包括%
)的二元运算符,所以你可以将%
定义为你想要的任意运算符(在你定义它的模块)。
作为最典型的例子,%
被Data.Ratio module作为Ratio
类型的构造函数提供。
在 GHCi 上尝试以下代码以确保 %
由 Data.Ratio
提供:
ghci> 3 % 9
<interactive>:1:3: error:
Variable not in scope: (%) :: Integer -> Integer -> t
ghci> import Data.Ratio
ghci> 3 % 9
1 % 3
请记住,您可以在这些搜索引擎中搜索此类运算符和函数:
其实我查过 %
是如何被 Hoogle 定义的。
% 是定义为
的中缀函数(%) :: Integral a => a -> a -> Ratio a
并且从上面的类型定义中,您可以看到它是 Data.Ratio
库的一部分,该库主要处理比率(即:分数)。它的代码是
x % y = reduce (x * signum y) (abs y)
因此给定两个积分 (x,y) ,它 returns 一个不可约分数 x/y
Data.Ratio
使用 %
作为构造函数,但除非该类型是在 Integral
类型 class 之前定义的,否则它无法解释为什么 %
可用 供 Data.Ratio
使用。 (当然,合格的导入允许您在多个模块中使用相同的运算符名称,所以无论哪种方式,%
被 Data.Ratio
使用都不是真正的理由。)
但是请注意,Integral
定义了 both mod
and rem
functions。我怀疑 %
被故意排除在 Integral
之外,都是为了避免 1) 选择它是否应该是 mod
或 rem
的别名,以及as 2) 让人们记住做出的选择。
另外,languages use different definitions for %
,所以 (%) = mod
或 (%) = rem
都有可能混淆 某人 。
在“老派”戴维斯 Introduction to Functional Programming Systems Using Haskell 中找到此内容。 (他经常拿Haskell比作Pascal。)这是对栈运算的模拟
type Stack = [Float]
push :: Float -> Stack -> Stack
push x stack = x : stack
addStack :: Stack -> Stack
addStack (x:y:stack) = (y + x) : stack
subtStack :: Stack -> Stack
subtStack (x:y:stack) = (y - x) : stack
multStack :: Stack -> Stack
multStack (x:y:stack) = (y * x) : stack
divStack :: Stack -> Stack
divStack (x:y:stack) = (y / x) : stack
emptyStack :: Stack
emptyStack = []
popStack :: Stack -> (Float, Stack)
popStack (top:rest) = (top,rest)
然后
let f % g = g . f
actionsOn = push 12.2 %
push 7.1 %
push 6.7 %
divStack %
push 4.3 %
subtStack %
multStack %
push 2.2 %
addStack
in popStack (actionsOn emptyStack)
(-37.331642,[])
这只是看起来很疯狂的嵌套函数的简洁版本
popStack (addStack (push 2.2 (multStack (subtStack (push 4.3 (divStack (push 6.7 (push 7.1 (push 12.2 emptyStack)))))))))
它本身避免为每个堆栈操作创建和传递新堆栈。总而言之,YAMAMOTO Yuji 一开始所说的适用于此,而不是任何 Ratio
东西 AFAIK。