Church numerals: Difference between revisions
Content added Content deleted
GordonBGood (talk | contribs) (→All closures and a union for type-punning: Nim, simplify and improve code...) |
GordonBGood (talk | contribs) (→{{header|Haskell}}: Add more complex Church functions and comments...) |
||
Line 666: | Line 666: | ||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
<lang haskell>--------------------- CHURCH NUMERALS -------------------- |
|||
The following code implements the more complex Church functions using `unsafeCoerce` to avoid non-decidable infinite types: |
|||
<lang haskell>import Unsafe.Coerce ( unsafeCoerce ) |
|||
type Church a = (a -> a) -> a -> a |
|||
churchZero :: Church a |
|||
churchZero = const id |
churchZero = const id |
||
churchOne :: Church a |
|||
churchSucc = (<*>) (.) |
|||
churchOne = id |
|||
succChurch :: Church a -> Church a |
|||
churchAdd = (<*>) . fmap (.) |
|||
succChurch = (<*>) (.) -- add one recursion, or \ ch f -> f . ch f |
|||
addChurch :: Church a -> Church a -> Church a |
|||
churchMult = (.) |
|||
addChurch = (<*>). fmap (.) -- or \ ach bch f -> ach f . bch f |
|||
multChurch :: Church a -> Church a -> Church a |
|||
churchExp = flip id |
|||
multChurch = (.) -- or \ ach bch -> ach . bch |
|||
expChurch :: Church a -> Church a -> Church a |
|||
expChurch basech expch = unsafeCoerce expch basech |
|||
isChurchZero :: Church a -> Church a |
|||
isChurchZero ch = unsafeCoerce ch (const churchZero) churchOne |
|||
predChurch :: Church a -> Church a |
|||
predChurch ch f x = unsafeCoerce ch (\ g h -> h (g f)) (const x) id |
|||
minusChurch :: Church a -> Church a -> Church a |
|||
minusChurch ach bch = unsafeCoerce bch predChurch ach |
|||
-- counts the times divisor can be subtracted from dividend to zero... |
|||
divChurch :: Church a -> Church a -> Church a |
|||
divChurch dvdnd dvsr = |
|||
let divr n d = |
|||
(\ v -> v (const $ succChurch $ divr v d) -- if branch |
|||
churchZero -- else branch |
|||
) (minusChurch n d) |
|||
in divr (unsafeCoerce succChurch dvdnd) $ unsafeCoerce dvsr |
|||
churchFromInt :: Int -> Church a |
|||
churchFromInt 0 = churchZero |
churchFromInt 0 = churchZero |
||
churchFromInt n = |
churchFromInt n = succChurch $ churchFromInt (n - 1) |
||
-- Or as a fold: |
-- Or as a fold: |
||
Line 686: | Line 716: | ||
-- Or as an iterated application: |
-- Or as an iterated application: |
||
-- churchFromInt n = iterate |
-- churchFromInt n = iterate succChurch churchZero !! n |
||
intFromChurch :: |
intFromChurch :: Church Int -> Int |
||
intFromChurch |
intFromChurch ch = ch succ 0 |
||
------------------------------------- TEST ------------------------------------- |
|||
--------------------------- TEST ------------------------- |
|||
main :: IO () |
main :: IO () |
||
main = do |
main = do |
||
let [cThree, cFour] = churchFromInt <$> [3, 4] |
let [cThree, cFour, cEleven, cTwelve] = churchFromInt <$> [3, 4, 11, 12] |
||
print $ fmap intFromChurch [ addChurch cThree cFour |
|||
print $ |
|||
, multChurch cThree cFour |
|||
fmap |
|||
, expChurch cFour cThree |
|||
intFromChurch |
|||
, expChurch cThree cFour |
|||
, isChurchZero churchZero |
|||
churchMult cThree cFour, |
|||
, predChurch cFour |
|||
churchExp cFour cThree, |
|||
, minusChurch cEleven cThree |
|||
churchExp cThree cFour |
|||
, divChurch cEleven cThree |
|||
]</lang> |
|||
, divChurch cTwelve cThree |
|||
]</lang> |
|||
{{Out}} |
{{Out}} |
||
<pre>[7,12,64, |
<pre>[7, 12, 81, 64, 1, 0, 3, 8, 3, 4]</pre> |
||
Note that Haskell has directly recursive functions so the y-Combinator is not used to implement recursion in the Church division function. |
|||
This version should be suitable to translation to most statically typed languages supporting first class closure functions using casting and/or type "punning" to eliminate the infinite types problems such as is done in the second Nim contribution. |
|||
==={{header|Use of RankNTypes to Avoid Coercion}}=== |
|||
The following code uses a wrapper `newtype` and the "RankNTypes" GHC Haskell extension to avoid the requirement for the unsafe coercion used above: |
|||
<lang haskell>{-# LANGUAGE RankNTypes #-} |
|||
newtype Church = Church { unChurch :: forall a. (a -> a) -> a -> a } |
|||
churchZero :: Church |
|||
churchZero = Church $ const id |
|||
succChurch :: Church -> Church |
|||
succChurch ch = Church $ (<*>) (.) $ unChurch ch -- add one recursion |
|||
addChurch :: Church -> Church -> Church |
|||
addChurch ach bch = |
|||
Church $ ((<*>) . fmap (.)) (unChurch ach) (unChurch bch) |
|||
multChurch :: Church -> Church -> Church |
|||
multChurch ach bch = Church $ unChurch ach . unChurch bch |
|||
expChurch :: Church -> Church -> Church |
|||
expChurch basech expch = Church $ unChurch expch $ unChurch basech |
|||
predChurch :: Church -> Church |
|||
predChurch ch = Church $ \ f x -> |
|||
unChurch ch (\ g h -> h (g f)) (const x) id |
|||
minusChurch :: Church -> Church -> Church |
|||
minusChurch ach bch = unChurch bch predChurch ach |
|||
isChurchZero :: Church -> Church |
|||
isChurchZero ch = unChurch ch (const churchZero) $ Church id |
|||
divChurch :: Church -> Church -> Church |
|||
divChurch dvdnd dvsr = |
|||
let divr n = |
|||
(\ v -> unChurch v |
|||
(const $ succChurch $ divr v) |
|||
churchZero |
|||
)(minusChurch n dvsr) |
|||
in divr (succChurch dvdnd) |
|||
churchFromInt :: Int -> Church |
|||
churchFromInt 0 = churchZero |
|||
churchFromInt n = succChurch $ churchFromInt (n - 1) |
|||
-- Or as a fold: |
|||
-- churchFromInt n = foldr (.) id . replicate n |
|||
-- Or as an iterated application: |
|||
-- churchFromInt n = iterate succChurch churchZero !! n |
|||
intFromChurch :: Church -> Int |
|||
intFromChurch ch = unChurch ch succ 0 |
|||
------------------------------------- TEST ------------------------------------- |
|||
main :: IO () |
|||
main = do |
|||
let [cThree, cFour, cEleven, cTwelve] = churchFromInt <$> [3, 4, 11, 12] |
|||
print $ fmap intFromChurch [ addChurch cThree cFour |
|||
, multChurch cThree cFour |
|||
, expChurch cFour cThree |
|||
, expChurch cThree cFour |
|||
, isChurchZero churchZero |
|||
, predChurch cFour |
|||
, minusChurch cEleven cThree |
|||
, divChurch cEleven cThree |
|||
, divChurch cTwelve cThree |
|||
]</lang> |
|||
{{out}} |
|||
<pre>[7, 12, 81, 64, 1, 0, 3, 8, 3, 4]</pre> |
|||
Note that Haskell has directly recursive functions so the y-Combinator is not used to implement recursion in the Church division function. |
|||
=={{header|Java}}== |
=={{header|Java}}== |