More info in blog post.
Run with
ghc -threaded -O2 -rtsopts measure.hs
cat pi.blc | ./measure +RTS -NYou may also be interested in an Effekt variant using effectful NbE: https://gist.github.com/marvinborner/44236c67bbcfdaa184f37bc9b784a73f
More info in blog post.
Run with
ghc -threaded -O2 -rtsopts measure.hs
cat pi.blc | ./measure +RTS -NYou may also be interested in an Effekt variant using effectful NbE: https://gist.github.com/marvinborner/44236c67bbcfdaa184f37bc9b784a73f
| 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 |