4

I'm used to using % to mean "modulo" in other languages. In Haskell, we have to use mod x y or x `mod` y. So, what is this symbol used for in Haskell?

Ryan
  • 1,486
  • 4
  • 18
  • 28
  • 1
    Show an example of its use. I don't remember any uses for it offhand, but it's very possible to make your own definition of it, so libraries may define it. – Carcigenicate Feb 19 '19 at 00:59
  • 2
    it's in `Data.Ratio`, see here: http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Ratio.html#v:-37- (Unless of course there is another definition of `%` in another library, as is entirely possible.) – Robin Zigmond Feb 19 '19 at 01:03

5 Answers5

11

With a quick look on Hoogle, you can see that % is an infix function defined as

(%) :: Integral a => a -> a -> Ratio a

and as you can guess it is part of the Data.Ratio library, which mostly deals with ratios (i.e.: fractions). It is code is

x % y = reduce (x * signum y) (abs y)

thus given two integrals (x,y) , it returns an irreducible fraction x/y

Lorenzo
  • 2,160
  • 12
  • 29
  • Never heard of Hoogle. I am new to Haskell. I searched via DDGo, and not one article mentioned Data.Ratio. This resource was not included in general search results. See: https://duckduckgo.com/?q=operator+haskell&t=ffab&atb=v155-6&ia=software – Ryan Feb 21 '19 at 22:22
  • Is there a way to look up those type definitions for Data.Ratio in GHCi/Prelude? I already tried `:t %` to no avail – Ryan Feb 21 '19 at 22:24
  • 1
    @Ryan, Hoogle at https://www.haskell.org/hoogle/ is a search engine for Haskell libraries. you can reach it at that link and you can then search for any function, some function description and -- the most important -- function types. As I said, `%` is part of the `Data.Ratio` library, so before you can use it in the GHCi -- including `:t`, you need to import it by `import Data.Ratio`. Then you can see the type. Remember also you can use `:info` that sometimes gives you more info than just `:t` – Lorenzo Feb 21 '19 at 22:39
6

In Haskell, we can define binary operators with various symbols (including %) like ordinary functions, So you can define % as an arbitrary operator you want (in the module which you define it).

As the most typical case, % is provided as the constructor of the Ratio type by Data.Ratio module.

Try the code below on GHCi to make sure that % is provided by 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

And remember you can search such operators and functions in these search engines:

Actually I've looked up how % is defined by Hoogle.

% is an infix function defined as

(%) :: Integral a => a -> a -> Ratio a

and from the type definition above, you can see that it is part of the Data.Ratio library, which mostly deals with ratios (i.e.: fractions). Its code is

x % y = reduce (x * signum y) (abs y)

thus given two integrals (x,y) , it returns an irreducible fraction x/y

Ryan
  • 1,486
  • 4
  • 18
  • 28
YAMAMOTO Yuji
  • 1,364
  • 9
  • 17
2

Searching for (%) on Stackage Hoogle, it appears that Data.Ratio defines the % operator as constructing a Ratio value from a numerator and denominator. A GHCi example:

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
bradrn
  • 8,337
  • 2
  • 22
  • 51
1

Data.Ratio uses % as a constructor, but unless that type was defined before the Integral type class, it doesn't explain why % was available for use by Data.Ratio. (Of course, qualified imports allow you to use the same operator name in multiple modules, so either way, % being used by Data.Ratio isn't really a reason.)

Note, however, that Integral defines both mod and rem functions. I suspect that % was intentionally left out of Integral, both to avoid 1) making a choice as to whether it should be an alias for mod or rem, as well as 2) making people remember which choice was made.

Also, languages use different definitions for %, so either (%) = mod or (%) = rem had the potential for confusing someone.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • There's also a nice version (I think maybe in Python?) that guarantees a positive result regardless of the signs of the operands, as well as guaranteeing `q * n + r = m`. – dfeuer Feb 20 '19 at 01:12
  • Python `%` is Haskell `mod`, I believe. – chepner Feb 20 '19 at 01:37
  • Huh. Got that wrong. R6RS Scheme's `mod` does it "Euclidean style", as does PureScript (which used to do it Knuth style but switched). – dfeuer Feb 20 '19 at 01:59
1

Found this in "Old School" Davies Introduction to Functional Programming Systems Using Haskell. (He constantly compares Haskell to Pascal.) It's a simulation of stack arithmetic

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)

Then

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,[])

This is just a neater version of a crazy-looking nested function

popStack (addStack (push 2.2 (multStack (subtStack (push 4.3 (divStack (push 6.7 (push 7.1 (push 12.2 emptyStack)))))))))

which itself avoids creating and passing a new stack for each stack operation. In summary, what YAMAMOTO Yuji says right at the beginning is applicable here and not really any Ratio stuff AFAIK.

147pm
  • 2,137
  • 18
  • 28