Skip to content

Instantly share code, notes, and snippets.

@mdiep
Created November 2, 2024 23:07
Show Gist options
  • Select an option

  • Save mdiep/ee0043eeb12431ed076658fca0fcb091 to your computer and use it in GitHub Desktop.

Select an option

Save mdiep/ee0043eeb12431ed076658fca0fcb091 to your computer and use it in GitHub Desktop.
Bitwise Operations in Dhall
let P =
{ List =
https://raw.githubusercontent.com/dhall-lang/dhall-lang/v23.0.0/Prelude/List/package.dhall
, Natural =
https://raw.githubusercontent.com/dhall-lang/dhall-lang/v23.0.0/Prelude/Natural/package.dhall
}
let modulo
: Natural Natural Natural
= λ(divisor : Natural)
λ(n : Natural)
P.Natural.fold
n
Natural
( λ(x : Natural)
if P.Natural.greaterThanEqual x divisor
then P.Natural.subtract divisor x
else x
)
n
let moduleExamples =
{ _2_1 = assert : modulo 2 1 1
, _2_2 = assert : modulo 2 2 0
, _2_3 = assert : modulo 2 3 1
}
let pow
: Natural Natural Natural
= λ(exponent : Natural)
λ(n : Natural)
if P.Natural.equal exponent 0
then 1
else P.Natural.fold
(P.Natural.subtract 1 exponent)
Natural
(λ(x : Natural) n * x)
n
let powExamples =
{ _2_0 = assert : pow 2 0 0
, _0_2 = assert : pow 0 2 1
, _1_2 = assert : pow 1 2 2
, _2_2 = assert : pow 2 2 4
, _3_3 = assert : pow 3 3 27
}
let toBits
: Natural Natural List Bool
= λ(size : Natural)
λ(n : Natural)
let State
: Type
= { bits : List Bool, remaining : Natural }
let initial
: State
= { bits = [] : List Bool, remaining = modulo (pow size 2) n }
let compute
: State State
= λ(state : State)
let bit
: Natural
= P.Natural.subtract (1 + List/length Bool state.bits) size
let bitValue
: Natural
= pow bit 2
in if P.Natural.greaterThanEqual state.remaining bitValue
then { bits = state.bits # [ True ]
, remaining =
P.Natural.subtract bitValue state.remaining
}
else { bits = state.bits # [ False ]
, remaining = state.remaining
}
let result
: State
= P.Natural.fold size State compute initial
in result.bits
let toBitsExamples =
{ _1_0 = assert : toBits 1 0 [ False ]
, _1_1 = assert : toBits 1 1 [ True ]
, _2_2 = assert : toBits 2 2 [ True, False ]
, _2_3 = assert : toBits 2 3 [ True, True ]
, _8_0 =
assert
: toBits 8 0
[ False, False, False, False, False, False, False, False ]
, _8_1 =
assert
: toBits 8 1
[ False, False, False, False, False, False, False, True ]
, _8_2 =
assert
: toBits 8 2
[ False, False, False, False, False, False, True, False ]
, _8_3 =
assert
: toBits 8 3
[ False, False, False, False, False, False, True, True ]
, _3_4 = assert : toBits 3 4 [ True, False, False ]
, _3_6 = assert : toBits 3 6 [ True, True, False ]
, _overflow = assert : toBits 3 8 toBits 3 0
}
let fromBits
: List Bool Natural
= λ(bits : List Bool)
let State
: Type
= { n : Natural, remaining : List Bool }
let Indexed
: Type
= { index : Natural, value : Bool }
let fold
: Indexed Natural Natural
= λ(bit : Indexed)
λ(value : Natural)
value + (if bit.value then pow bit.index 2 else 0)
let result
: Natural
= List/fold
Indexed
(List/indexed Bool (List/reverse Bool bits))
Natural
fold
0
in result
let fromBitsExamples =
{ _1_0 = assert : 0 fromBits [ False ]
, _1_1 = assert : 1 fromBits [ True ]
, _2_2 = assert : 2 fromBits [ True, False ]
, _2_3 = assert : 3 fromBits [ True, True ]
, _8_0 =
assert
: 0
fromBits
[ False, False, False, False, False, False, False, False ]
, _8_1 =
assert
: 1
fromBits [ False, False, False, False, False, False, False, True ]
, _8_2 =
assert
: 2
fromBits [ False, False, False, False, False, False, True, False ]
, _8_3 =
assert
: 3
fromBits [ False, False, False, False, False, False, True, True ]
}
let bitwiseCompare
: Natural (Bool Bool Bool) Natural Natural Natural
= λ(size : Natural)
λ(compare : Bool Bool Bool)
λ(a : Natural)
λ(b : Natural)
let zipped = P.List.zip Bool (toBits size a) Bool (toBits size b)
let compared =
P.List.map
{ _1 : Bool, _2 : Bool }
Bool
( λ(tuple : { _1 : Bool, _2 : Bool })
compare tuple._1 tuple._2
)
zipped
in fromBits compared
let or
: Natural Natural Natural Natural
= λ(size : Natural)
bitwiseCompare size (λ(a : Bool) λ(b : Bool) a || b)
let orExample = assert : or 8 4 6 6
let xor
: Natural Natural Natural Natural
= λ(size : Natural)
bitwiseCompare size (λ(a : Bool) λ(b : Bool) a != b)
let xorExample = assert : xor 8 4 6 2
let and
: Natural Natural Natural Natural
= λ(size : Natural)
bitwiseCompare size (λ(a : Bool) λ(b : Bool) a && b)
let andExample = assert : and 8 4 6 4
let shiftLeft
: Natural Natural Natural Natural
= λ(size : Natural)
λ(shift : Natural)
λ(n : Natural)
let bits
: List Bool
= toBits size n
let shifted =
P.List.drop shift Bool bits # P.List.replicate shift Bool False
in fromBits shifted
let shiftLeftExample = assert : shiftLeft 3 2 5 4
let shiftRight
: Natural Natural Natural Natural
= λ(size : Natural)
λ(shift : Natural)
λ(n : Natural)
let bits
: List Bool
= toBits size n
let shifted =
List/reverse
Bool
(P.List.drop shift Bool (List/reverse Bool bits))
in fromBits shifted
let shiftRightExample = assert : shiftRight 3 2 7 1
in { and, or, shiftLeft, shiftRight, xor }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment