Skip to content

Instantly share code, notes, and snippets.

View AndrasKovacs's full-sized avatar

András Kovács AndrasKovacs

View GitHub Profile
@AndrasKovacs
AndrasKovacs / longest_common_subseq.hs
Last active December 10, 2015 10:09
Longest common subsequences in Haskell. Direct translation of the standard DP algorithm to folds on recursively defined lists. It looks horrible, but it's pretty straightforward. For example, "m01" means an element in the table with (i - 0, j - 1) index, where (i, j) is the current index (although there is no actual table, only lists).
import Data.List (foldl', zipWith4)
lcs :: (Eq a) => [a] -> [a] -> [a]
lcs as bs = reverse . snd . last $ foldl' byRow ((0::Int, []):[(0, []) | _ <- as]) bs where
byRow m11s@(empty:m10s) b = scanl byCol empty (zip3 m11s m10s as) where
byCol m01@(m01_l, _) ((m11_l, m11_str), m10@(m10_l, _), a)
| a == b = (m11_l + 1, a : m11_str)
| otherwise = if m01_l > m10_l then m01 else m10
-- Here we use zipWith4 instead of scanl. It's faster by 20-50 percent.
@AndrasKovacs
AndrasKovacs / pp_addRomans.hs
Last active December 11, 2015 13:18
Adding together two roman numerals to get a third one. See at: http://programmingpraxis.com/2009/03/06/roman-numerals/
import Data.Map (fromList, (!))
romans = zip (words "M CM D CD C XC L XL X IX V IV I") [1000,900,500,400,100,90,50,40,10,9,5,4,1]
romMap = fromList romans
toRoman = go romans where
go _ 0 = ""
go a@((r, c):rs) n | c <= n = r ++ go a (n - c)
| otherwise = go rs n
@AndrasKovacs
AndrasKovacs / bruteSudoku.hs
Last active December 14, 2015 04:08
Small brute Sudoku solver. The input is a flattened 9x9 table as a string where "0" denotes an empty cell. O/O2 compilation is advised for good performance. The solver may return multiple solutions (though a proper Sudoku table should be unambiguous).
import Data.Array.Unboxed
import Data.Array.Base (unsafeAt)
import Data.List.Split
import Data.List
type Table = UArray Int Char
solve :: String -> [String]
solve = map elems . go 0 . listArray (0, 80) where
{-# LANGUAGE TupleSections, RecordWildCards #-}
import Prelude hiding (lookup)
import Control.Arrow (first)
data TTree k v = TTree {val :: !(Maybe v), node :: !(TNode k v)} deriving Show
data TNode k v = Empty | Node {key :: !k, lch, eqch, rch :: !(TTree k v)} deriving Show
empty :: TTree k v
empty = TTree Nothing Empty
import Data.Function (on)
data Leftist a = Empty | Node {_rank :: Int, val :: a, lch, rch :: (Leftist a)}
rank :: Leftist a -> Int
rank (Node r _ _ _) = r
rank _ = 0
singleton :: a -> Leftist a
singleton a = Node 1 a Empty Empty
{-# LANGUAGE TupleSections, DeriveTraversable, DeriveFoldable, DeriveFunctor #-}
import Control.Monad.State
import Data.Traversable
import Data.Foldable
import qualified Data.Map as M
data Tree a = Empty | Tree a (Tree a) (Tree a)
deriving (Show, Functor, Foldable, Traversable)
@AndrasKovacs
AndrasKovacs / BidirectionalZipper.hs
Last active December 15, 2015 21:29
Generic bidirectional zipper for any Traversable. Based on Oleg Kiselyov's article: http://okmij.org/ftp/continuations/zipper.html#traversable I've no idea currently whether this has decent performance. It goes leftward by reverting to a saved previous continuation, while also saving the edits we've made on nodes to the right.
import qualified Data.Traversable as T
import Control.Monad.Cont
data Zipper t a = ZDone (t a) | Zipper a (Maybe a -> Zipper t a)
data BiZip t a = BiZip [Maybe a] -- edits we've done on the left
[Maybe a] -- edits we've done on the right
[Zipper t a] -- saved Zippers from the left edits
mkZipper :: T.Traversable t => t a -> Zipper t a
mkZipper t = (`runCont` id) $ T.mapM yield t >>= return . ZDone
@AndrasKovacs
AndrasKovacs / DiningPhilosophersSTM.hs
Last active December 16, 2015 16:49
Dining philosophers solution with STM.
import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM
import System.Random
import Text.Printf
philosophers = ["Aristotle", "Kant", "Spinoza", "Marx", "Russel"]
waitSome = randomRIO (1000, 5000) >>= threadDelay . (*1000)
@AndrasKovacs
AndrasKovacs / BinTreeOptions.hs
Last active December 17, 2015 03:09
Pricing options with a binary tree approximation (CRR). Branches with very small differences in share price (beyond the precision of 64bit floats) are treated as equal and thus not recomputed.
import Text.Printf
import Control.Monad.State.Strict
import qualified Data.HashMap.Strict as HM
data OptType = Call | Put deriving (Show, Enum)
data Continent = Am | Eur deriving (Show, Enum)
optPrice optType continent s k sigma rf dt n divPayments = let
u = exp (sigma * sqrt dt)
d = 1 / u
@AndrasKovacs
AndrasKovacs / GameOfLife.hs
Last active December 17, 2015 09:59
Conway's Game Of Life.
import qualified Data.Set as S
import qualified Data.Map as M
import Control.Monad
import Data.Bool
step :: S.Set (Int, Int) -> S.Set (Int, Int)
step grid = let
neighs (i, j) = [((i + di, j + dj), 1) |
(di, dj) <- tail $ liftM2 (,) [0, -1, 1] [0, -1, 1]]
freqs = M.fromListWith (+) $ neighs =<< S.toList grid