Skip to content

Instantly share code, notes, and snippets.

@marvinborner
Last active March 14, 2025 13:23
Show Gist options
  • Save marvinborner/be9c212ebf717441b708735bb308a88c to your computer and use it in GitHub Desktop.
Save marvinborner/be9c212ebf717441b708735bb308a88c to your computer and use it in GitHub Desktop.
Measure the area of fractals in Lambda Screen
import Control.Parallel.Strategies ( parMap
, rdeepseq
)
import Data.List ( (!?) )
import Data.Map ( Map )
import qualified Data.Map as Map
data Term = Abs Int Term | App Term Term | Var Int
data HTerm = HAbs (HTerm -> HTerm) | HApp HTerm HTerm | HVar Int
maxLayer :: Int
maxLayer = 4
app :: HTerm -> HTerm -> HTerm
app (HAbs f) = f
app f = HApp f
higher :: Term -> HTerm
higher = go Map.empty
where
go env (Var x) = case Map.lookup x env of
Just v -> v
_ -> HVar x
go env (Abs n t) = HAbs $ \x -> go (Map.insert n x env) t
go env (App a b) = app (go env a) (go env b)
lower :: HTerm -> Term
lower = go 0
where
go _ (HVar v ) = Var v
go d (HAbs t ) = Abs d $ go (d + 1) (t (HVar d))
go d (HApp a b) = App (go d a) (go d b)
screens :: Term -> Maybe [Term]
screens (Abs n t) = go t
where
go (App a b) = (b :) <$> go a
go (Var v) | v == n = Just []
go _ = Nothing
screens _ = Nothing
isPerfect :: Int -> Bool
isPerfect n = square * square == n
where square = floor $ sqrt (fromIntegral n :: Double)
isWhite :: Term -> Bool
isWhite (Abs n (Abs _ (Var v))) = n == v
isWhite _ = False
isBlack :: Term -> Bool
isBlack (Abs _ (Abs n (Var v))) = n == v
isBlack _ = False
area :: Int -> Double -> HTerm -> Double
area maxLayer = go 0
where
go layer size _ | layer > maxLayer = 0
go layer size t = case screens t' of
Just s | isPerfect (length s) -> do
let slice = size / (fromIntegral (length s) :: Double)
sum $ parMap rdeepseq (go (layer + 1) slice . higher) s -- parallel `sum $ map (go slice . higher) s`
Nothing | isBlack t' -> size -- here we only count black area, you can modify this of course!
| isWhite t' -> 0
| otherwise -> error "invalid screen"
where t' = lower t
-- | quick'n'dirty BLC parser
fromBinary :: String -> Term
fromBinary = fst . go [] 0
where
go env n inp = case inp of
'0' : '0' : rst -> do
let (e, rst1) = go (n : env) (n + 1) rst
(Abs n e, rst1)
'0' : '1' : rst -> do
let (a, rst1) = go env n rst
let (b, rst2) = go env n rst1
(App a b, rst2)
'1' : rst -> do
let idx = length (takeWhile (== '1') rst)
case env !? idx of
Just v -> (Var v, drop (idx + 1) rst)
Nothing -> error "open term"
_ -> error $ "invalid " ++ inp
main :: IO ()
main = do
blc <- getContents
let t = fromBinary blc
let x = area maxLayer 1.0 $ higher $ App t (Var 0)
print $ (1 - x) * 4
00010100011010000000010111001110000110010111110111100000011100111001011111101101000000101111000001010000001110011100111010
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment