Last active
December 14, 2015 08:48
-
-
Save sebfisch/5060428 to your computer and use it in GitHub Desktop.
Revisions
-
Sebastian Fischer revised this gist
Mar 1, 2013 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -126,4 +126,5 @@ We can reason as follows to simplify combined mappers: (glob "*.scala" "*.hs" >>> glob "Mapper.*" "Mappers.*") = (identity &&& glob "*.scala" "*.hs") >>> glob "Mapper.*" "Mappers.*" -} -
Sebastian Fischer revised this gist
Mar 1, 2013 . 1 changed file with 16 additions and 14 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -27,9 +27,8 @@ type Mapper = String -> [String] {- The combinator `&&&` composes two mappers by collecting their results in a list. `discard` is its unit. discard &&& m = m m &&& discard = m @@ -47,7 +46,8 @@ discard _ = [] {- The combinator `>>>` chains two mappers by applying the second mapper to every result of the first and collecting all results. `identity` is its unit. identity >>> m = m m >>> identity = m @@ -65,7 +65,7 @@ l >>> r = concatMap r . l {- Both `&&&` and `>>>` are associative operators. a &&& (b &&& c) = (a &&& b) &&& c a >>> (b >>> c) = (a >>> b) >>> c @@ -86,13 +86,16 @@ chained = foldr (>>>) identity `discard` is a zero of `>>>`. discard >>> m = discard m >>> discard = discard Composition distributes over chaining from the right. (a &&& b) >>> c = (a >>> c) &&& (b >>> c) It distributes from the left, if we ignore the order of computed results. sort . (a >>> (b &&& c)) = sort . ((a >>> b) &&& (a >>> c)) -} @@ -116,12 +119,11 @@ glob fromPat toPat = We can reason as follows to simplify combined mappers: glob "Mapper.*" "Mappers.*" &&& (glob "*.scala" "*.hs" >>> glob "Mapper.*" "Mappers.*") = (identity >>> glob "Mapper.*" "Mappers.*") &&& (glob "*.scala" "*.hs" >>> glob "Mapper.*" "Mappers.*") = (identity &&& glob "*.scala" "*.hs") >>> glob "Mapper.*" "Mappers.*" -} -
Sebastian Fischer revised this gist
Feb 28, 2013 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -122,6 +122,6 @@ We can reason as follows to simplify combined mappers: (glob "*.java" "*.scala" >>> identity) &&& (glob "*.java" "*.scala" >>> glob "*.scala" "*.hs") = glob "*.java" "*.scala" >>> (identity &&& glob "*.scala" "*.hs") -} -
Sebastian Fischer revised this gist
Feb 28, 2013 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -114,7 +114,7 @@ glob fromPat toPat = {- We can reason as follows to simplify combined mappers: glob "*.java" "*.scala" &&& (glob "*.java" "*.scala" >>> glob "*.scala" "*.hs") -
Sebastian Fischer revised this gist
Feb 28, 2013 . 1 changed file with 16 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -15,6 +15,7 @@ considering their implementation. -} module Mappers where @@ -109,3 +110,18 @@ glob fromPat toPat = case elemIndices '*' s of [] -> (s,"") ps -> (take (last ps) s, drop (last ps+1) s) {- Now, we can reason as follows to simplify combined mappers: glob "*.java" "*.scala" &&& (glob "*.java" "*.scala" >>> glob "*.scala" "*.hs") = (glob "*.java" "*.scala" >>> identity) &&& (glob "*.java" "*.scala" >>> glob "*.scala" "*.hs") = (glob "*.java" "*.scala" >>> (identity &&& glob "*.scala" "*.hs")) -} -
Sebastian Fischer created this gist
Feb 28, 2013 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,111 @@ {- A German blog post translating Java code for the build tool Ant to Scala http://funktionale-programmierung.de/2013/02/26/scala-java-ant.html made me translate the Scala code to Haskell. I added combinators for binary composition of mappers as well as a unit mapper for one of them. The code is still shorter. I find the Haskell version more readable because expressions and their types are separate rather than interleaved as in Scala. Defining binary operators where the Scala version only had variants on lists reveals algebraic properties that can be used to reason about mappers without considering their implementation. -} module Mappers where import Data.List (elemIndices) type Mapper = String -> [String] {- Mapper is a semiring. `&&&` is addition, `discard` is its unit. discard &&& m = m m &&& discard = m -} discard :: Mapper discard _ = [] (&&&) :: Mapper -> Mapper -> Mapper (l &&& r) s = l s ++ r s {- `>>>` is multiplication, `identity` is its unit. identity >>> m = m m >>> identity = m -} identity :: Mapper identity s = [s] (>>>) :: Mapper -> Mapper -> Mapper l >>> r = concatMap r . l {- Addition and multiplication are associative. a &&& (b &&& c) = (a &&& b) &&& c a >>> (b >>> c) = (a >>> b) >>> c -} composite :: [Mapper] -> Mapper composite = foldr (&&&) discard chained :: [Mapper] -> Mapper chained = foldr (>>>) identity {- `discard` is a zero of `>>>`. discard >>> m = discard m >>> discrad = discard Multiplication distributes over addition. a >>> (b &&& c) = (a >>> b) &&& (a >>> c) (a &&& b) >>> c = (a >>> c) &&& (b >>> c) -} glob :: String -> String -> Mapper glob fromPat toPat = \s -> [ toPre ++ mid ++ toPost | let (pre, rest) = splitAt (length fromPre) s (mid, post) = splitAt (length rest - length fromPost) rest, pre == fromPre, post == fromPost ] where (fromPre, fromPost) = splitAtLastStar fromPat (toPre, toPost) = splitAtLastStar toPat splitAtLastStar s = case elemIndices '*' s of [] -> (s,"") ps -> (take (last ps) s, drop (last ps+1) s)