From twilson at csufresno.edu Thu Aug 1 02:45:05 2019 From: twilson at csufresno.edu (Todd Wilson) Date: Wed, 31 Jul 2019 19:45:05 -0700 Subject: [Haskell-cafe] Performance best practices Message-ID: Dear Cafe: I'm getting to the point in my Haskell learning curve where I'm getting more interested in the fine points of programming for performance and would be grateful for some ideas of the tools and options available for exploring this. To make this concrete, let me give a simple example. Here are two different ways of coding the same list-splitting function: import Data.List (inits,tails) splits1, splits2 :: [a] -> [([a],[a])] splits1 xs = zip (inits xs) (tails xs) splits2 [] = [([],[])] splits2 xs@(x:xs') = ([],xs) : [(x:as,bs) | (as,bs) <- splits2 xs'] For example, splits1 [1,2,3] is [([],[1,2,3]),([1],[2,3]),([1,2],[3]),([1,2,3],[])]. How do these functions compare in their actual time and space usage? It seems that, asymptotically, tails is O(n) while inits is O(n^2) in both time and space (when fully evaluated), and splits2 is also O(n^2), but how would I go about comparing them in actual usage to get a more precise comparison? What profiling or run-time statistics could I gather to make a decision about which one to use in a situation where performance mattered (assuming for the sake of discussion that such a situation existed for this simple example)? And, out of curiosity, is there an even more efficient way to code this function? Thanks, Todd Wilson From jo at durchholz.org Thu Aug 1 05:50:17 2019 From: jo at durchholz.org (Joachim Durchholz) Date: Thu, 1 Aug 2019 07:50:17 +0200 Subject: [Haskell-cafe] ANN: To Kata Haskellen Evangelion In-Reply-To: References: <72ad2c39-ee1f-6456-8434-2f06c563e5ca@durchholz.org> <3ae44439-31a1-d702-a914-699593b42621@durchholz.org> Message-ID: Am 31.07.19 um 22:33 schrieb Vanessa McHale: > I'm not convinced that nontermination would be worth redesigning the > language - the research implementations seem rough. That all implementations are rough does not imply whether it's possible to do a smooth one or not, just that nobody has a working idea yet. E.g. it is possible that people try to leverage existing work (90% may try to use type system extensions, for example) and find that it is too unwieldy because the existing mechanisms aren't really suitable (e.g. it may be that type systems in general are not very well-suited to expressing termination properties, leading us to the observation that "research implementations seem rough"). > (Moreover, one of the advantages of laziness is precisely that one can > write a function like take that works on both streams and lists). That's exactly the relevant scenario. Strictly speaking, all functions that iterate over all elements of the list (say, takes its length) are buggy: They will not terminate if given an infinite list. The bad thing here is that in Haskell, generators and lists are exactly the same, so there is no way to make a non-buggy version of such a function. (AFAIK, which doesn't say much because I haven't looked deeply enough into Haskell in the last decade to be sure about this anymore. The language did evolve after all.) From jaro.reinders at gmail.com Thu Aug 1 07:58:15 2019 From: jaro.reinders at gmail.com (Jaro Reinders) Date: Thu, 1 Aug 2019 09:58:15 +0200 Subject: [Haskell-cafe] Performance best practices In-Reply-To: References: Message-ID: I think the best way to test the performance is to use a benchmarking library such as criterion (http://www.serpentine.com/criterion/) import Criterion.Main import Data.List (inits,tails) splits1, splits2, splits3 :: [a] -> [([a],[a])] splits1 xs = zip (inits xs) (tails xs) splits2 [] = [([],[])] splits2 xs@(x:xs') = ([],xs) : [(x:as,bs) | (as,bs) <- splits2 xs'] splits3 = go id where go prefix xs = (prefix [],xs) : case xs of x:xs -> go (prefix . (x :)) xs [] -> [] main = defaultMain [ bench "splits1" $ nf splits1 input , bench "splits2" $ nf splits2 input , bench "splits3" $ nf splits3 input ] where input :: [Int] input = [1..1000] It gives the following results on my computer: benchmarking splits1 time 4.693 ms (4.625 ms .. 4.752 ms) 0.999 R² (0.998 R² .. 0.999 R²) mean 4.725 ms (4.694 ms .. 4.758 ms) std dev 97.37 μs (77.95 μs .. 123.3 μs) benchmarking splits2 time 12.10 ms (11.96 ms .. 12.25 ms) 0.999 R² (0.999 R² .. 1.000 R²) mean 12.08 ms (12.03 ms .. 12.14 ms) std dev 149.7 μs (110.0 μs .. 199.1 μs) benchmarking splits3 time 4.110 ms (4.025 ms .. 4.187 ms) 0.997 R² (0.996 R² .. 0.999 R²) mean 4.124 ms (4.081 ms .. 4.177 ms) std dev 147.6 μs (115.6 μs .. 238.5 μs) variance introduced by outliers: 17% (moderately inflated) On 01-08-2019 04:45, Todd Wilson wrote: > Dear Cafe: > > I'm getting to the point in my Haskell learning curve where I'm > getting more interested in the fine points of programming for > performance and would be grateful for some ideas of the tools and > options available for exploring this. To make this concrete, let me > give a simple example. Here are two different ways of coding the same > list-splitting function: > > import Data.List (inits,tails) > splits1, splits2 :: [a] -> [([a],[a])] > splits1 xs = zip (inits xs) (tails xs) > splits2 [] = [([],[])] > splits2 xs@(x:xs') = ([],xs) : [(x:as,bs) | (as,bs) <- splits2 xs'] > > For example, splits1 [1,2,3] is > [([],[1,2,3]),([1],[2,3]),([1,2],[3]),([1,2,3],[])]. > > How do these functions compare in their actual time and space usage? > It seems that, asymptotically, tails is O(n) while inits is O(n^2) in > both time and space (when fully evaluated), and splits2 is also > O(n^2), but how would I go about comparing them in actual usage to get > a more precise comparison? What profiling or run-time statistics could > I gather to make a decision about which one to use in a situation > where performance mattered (assuming for the sake of discussion that > such a situation existed for this simple example)? And, out of > curiosity, is there an even more efficient way to code this function? > Thanks, > > Todd Wilson > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. > From jerzy.karczmarczuk at unicaen.fr Thu Aug 1 08:06:21 2019 From: jerzy.karczmarczuk at unicaen.fr (Jerzy Karczmarczuk) Date: Thu, 1 Aug 2019 10:06:21 +0200 Subject: [Haskell-cafe] ANN: To Kata Haskellen Evangelion In-Reply-To: References: <72ad2c39-ee1f-6456-8434-2f06c563e5ca@durchholz.org> <3ae44439-31a1-d702-a914-699593b42621@durchholz.org> Message-ID: <68790283-d740-ae88-1f6f-544c97203ea0@unicaen.fr> Le 01/08/2019 à 07:50, Joachim Durchholz a écrit : > Strictly speaking, all functions that iterate over all elements of the > list (say, takes its length) *are buggy*: They will not terminate if > given an infinite list. I think that you have a curious definition of the term "buggy". This definition is as buggy as the rest of the world (perhaps infinite...), or more. You like to play with words. Now the non-termination is "buggy". Previously the bottom (non-termination) was impure. Do you really want to save the humanity with such statements? Jerzy Karczmarczuk -------------- next part -------------- An HTML attachment was scrubbed... URL: From jaro.reinders at gmail.com Thu Aug 1 08:25:02 2019 From: jaro.reinders at gmail.com (Jaro Reinders) Date: Thu, 1 Aug 2019 10:25:02 +0200 Subject: [Haskell-cafe] Performance best practices In-Reply-To: References: Message-ID: If you fully evaluate the list produced by tails, then you're still spending O(n^2) time, because that is just the size of the produced list. But constructing the list and the memory taken by the list is O(n), because most of the lists are shared (https://wiki.haskell.org/Sharing). On 01-08-2019 04:45, Todd Wilson wrote: > It seems that, asymptotically, tails is O(n) while inits is O(n^2) in > both time and space (when fully evaluated) From jo at durchholz.org Thu Aug 1 08:49:06 2019 From: jo at durchholz.org (Joachim Durchholz) Date: Thu, 1 Aug 2019 10:49:06 +0200 Subject: [Haskell-cafe] ANN: To Kata Haskellen Evangelion In-Reply-To: <68790283-d740-ae88-1f6f-544c97203ea0@unicaen.fr> References: <72ad2c39-ee1f-6456-8434-2f06c563e5ca@durchholz.org> <3ae44439-31a1-d702-a914-699593b42621@durchholz.org> <68790283-d740-ae88-1f6f-544c97203ea0@unicaen.fr> Message-ID: Am 01.08.19 um 10:06 schrieb Jerzy Karczmarczuk: > > You like to play with words. Now the non-termination is > "buggy". Previously the bottom (non-termination) was impure. Do you > really want to save the humanity with such statements? Nice play with words. From jaro.reinders at gmail.com Thu Aug 1 09:04:19 2019 From: jaro.reinders at gmail.com (Jaro Reinders) Date: Thu, 1 Aug 2019 11:04:19 +0200 Subject: [Haskell-cafe] Performance best practices In-Reply-To: References: Message-ID: <204c1c06-4879-28ac-fd4b-abcdc3ea81b7@gmail.com> Replying to myself, you can actually write an evaluation function that forces all values in the result of tails and inits in linear time: -- force the result of tails in linear time seqTails (x:xs) = x `deepseq` seqList xs seqTails [] = () -- force all the values in a list to whnf in linear time -- https://wiki.haskell.org/Weak_head_normal_form seqList (x:xs) = x `seq` seqList xs seqList [] = () -- force the result of inits in linear time seqInits xs = last xs `deepseq` seqList xs Try it in ghci with :sprint (https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html#ghci-cmd-:sprint): > let x = tails [1..3::Int] > :sprint x x = _ > seqTails x () > :sprint x x = [[1,2,3],[2,3],[3],[]] > let y = inits [1..3::Int] > :sprint y y = _ > seqInits y () > :sprint y y = [[],[1],[1,2],[1,2,3]] Using criterion you can see that it is actually linear time: main = defaultMain [ bgroup "inits" [ bench "1000" $ whnf (seqInits . inits) [1..1000 :: Int] , bench "10000" $ whnf (seqInits . inits) [1..10000 :: Int] , bench "100000" $ whnf (seqInits . inits) [1..100000 :: Int] , bench "1000000" $ whnf (seqInits . inits) [1..1000000 :: Int] ] , bgroup "tails" [ bench "1000" $ whnf (seqTails . tails) [1..1000 :: Int] , bench "10000" $ whnf (seqTails . tails) [1..10000 :: Int] , bench "100000" $ whnf (seqTails . tails) [1..100000 :: Int] , bench "1000000" $ whnf (seqTails . tails) [1..1000000 :: Int] ] ] benchmarking inits/1000 time 204.2 μs (203.2 μs .. 205.4 μs) 1.000 R² (1.000 R² .. 1.000 R²) mean 203.4 μs (202.8 μs .. 204.1 μs) std dev 2.163 μs (1.755 μs .. 2.664 μs) benchmarking inits/10000 time 3.127 ms (3.107 ms .. 3.148 ms) 1.000 R² (0.999 R² .. 1.000 R²) mean 3.105 ms (3.088 ms .. 3.118 ms) std dev 45.73 μs (32.97 μs .. 69.14 μs) benchmarking inits/100000 time 41.05 ms (39.11 ms .. 42.87 ms) 0.993 R² (0.988 R² .. 0.998 R²) mean 41.52 ms (40.62 ms .. 42.46 ms) std dev 1.912 ms (1.330 ms .. 2.930 ms) variance introduced by outliers: 12% (moderately inflated) benchmarking inits/1000000 time 423.0 ms (318.2 ms .. 535.5 ms) 0.991 R² (0.969 R² .. 1.000 R²) mean 459.1 ms (428.8 ms .. 505.2 ms) std dev 44.05 ms (10.06 ms .. 58.49 ms) variance introduced by outliers: 22% (moderately inflated) benchmarking tails/1000 time 8.811 μs (8.768 μs .. 8.873 μs) 1.000 R² (0.999 R² .. 1.000 R²) mean 8.874 μs (8.819 μs .. 8.963 μs) std dev 225.7 ns (168.4 ns .. 325.2 ns) variance introduced by outliers: 28% (moderately inflated) benchmarking tails/10000 time 87.21 μs (86.85 μs .. 87.79 μs) 1.000 R² (0.999 R² .. 1.000 R²) mean 87.42 μs (87.01 μs .. 87.88 μs) std dev 1.481 μs (1.132 μs .. 1.953 μs) variance introduced by outliers: 11% (moderately inflated) benchmarking tails/100000 time 886.9 μs (882.9 μs .. 890.9 μs) 1.000 R² (1.000 R² .. 1.000 R²) mean 881.5 μs (878.1 μs .. 885.7 μs) std dev 12.40 μs (9.598 μs .. 18.97 μs) benchmarking tails/1000000 time 9.796 ms (9.757 ms .. 9.840 ms) 1.000 R² (1.000 R² .. 1.000 R²) mean 9.817 ms (9.791 ms .. 9.845 ms) std dev 78.47 μs (60.63 μs .. 99.31 μs) On 01-08-2019 10:25, Jaro Reinders wrote: > If you fully evaluate the list produced by tails, then you're still > spending O(n^2) time, because that is just the size of the produced > list. But constructing the list and the memory taken by the list is > O(n), because most of the lists are shared > (https://wiki.haskell.org/Sharing). > > On 01-08-2019 04:45, Todd Wilson wrote: >> It seems that, asymptotically, tails is O(n) while inits is O(n^2) in >> both time and space (when fully evaluated) From jaro.reinders at gmail.com Thu Aug 1 09:24:45 2019 From: jaro.reinders at gmail.com (Jaro Reinders) Date: Thu, 1 Aug 2019 11:24:45 +0200 Subject: [Haskell-cafe] Performance best practices In-Reply-To: <204c1c06-4879-28ac-fd4b-abcdc3ea81b7@gmail.com> References: <204c1c06-4879-28ac-fd4b-abcdc3ea81b7@gmail.com> Message-ID: <8e0e3b02-be54-9d88-a30e-add0bb8d9b13@gmail.com> I just realized seqTails and seqInits are unnecessary, seqList is enough. On 01-08-2019 11:04, Jaro Reinders wrote: > Replying to myself, you can actually write an evaluation function that > forces all values in the result of tails and inits in linear time: > > -- force the result of tails in linear time > seqTails (x:xs) = x `deepseq` seqList xs > seqTails [] = () > > -- force all the values in a list to whnf in linear time > -- https://wiki.haskell.org/Weak_head_normal_form > seqList (x:xs) = x `seq` seqList xs > seqList [] = () > > -- force the result of inits in linear time > seqInits xs = last xs `deepseq` seqList xs > > Try it in ghci with :sprint > (https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html#ghci-cmd-:sprint): > > > let x = tails [1..3::Int] > > :sprint x > x = _ > > seqTails x > () > > :sprint x > x = [[1,2,3],[2,3],[3],[]] > > > let y = inits [1..3::Int] > > :sprint y > y = _ > > seqInits y > () > > :sprint y > y = [[],[1],[1,2],[1,2,3]] > > Using criterion you can see that it is actually linear time: > > main = defaultMain > [ bgroup "inits" > [ bench "1000" $ whnf (seqInits . inits) [1..1000 :: Int] > , bench "10000" $ whnf (seqInits . inits) [1..10000 :: Int] > , bench "100000" $ whnf (seqInits . inits) [1..100000 :: Int] > , bench "1000000" $ whnf (seqInits . inits) [1..1000000 :: Int] > ] > , bgroup "tails" > [ bench "1000" $ whnf (seqTails . tails) [1..1000 :: Int] > , bench "10000" $ whnf (seqTails . tails) [1..10000 :: Int] > , bench "100000" $ whnf (seqTails . tails) [1..100000 :: Int] > , bench "1000000" $ whnf (seqTails . tails) [1..1000000 :: Int] > ] > ] > > > benchmarking inits/1000 > time 204.2 μs (203.2 μs .. 205.4 μs) > 1.000 R² (1.000 R² .. 1.000 R²) > mean 203.4 μs (202.8 μs .. 204.1 μs) > std dev 2.163 μs (1.755 μs .. 2.664 μs) > > benchmarking inits/10000 > time 3.127 ms (3.107 ms .. 3.148 ms) > 1.000 R² (0.999 R² .. 1.000 R²) > mean 3.105 ms (3.088 ms .. 3.118 ms) > std dev 45.73 μs (32.97 μs .. 69.14 μs) > > benchmarking inits/100000 > time 41.05 ms (39.11 ms .. 42.87 ms) > 0.993 R² (0.988 R² .. 0.998 R²) > mean 41.52 ms (40.62 ms .. 42.46 ms) > std dev 1.912 ms (1.330 ms .. 2.930 ms) > variance introduced by outliers: 12% (moderately inflated) > > benchmarking inits/1000000 > time 423.0 ms (318.2 ms .. 535.5 ms) > 0.991 R² (0.969 R² .. 1.000 R²) > mean 459.1 ms (428.8 ms .. 505.2 ms) > std dev 44.05 ms (10.06 ms .. 58.49 ms) > variance introduced by outliers: 22% (moderately inflated) > > > > benchmarking tails/1000 > time 8.811 μs (8.768 μs .. 8.873 μs) > 1.000 R² (0.999 R² .. 1.000 R²) > mean 8.874 μs (8.819 μs .. 8.963 μs) > std dev 225.7 ns (168.4 ns .. 325.2 ns) > variance introduced by outliers: 28% (moderately inflated) > > benchmarking tails/10000 > time 87.21 μs (86.85 μs .. 87.79 μs) > 1.000 R² (0.999 R² .. 1.000 R²) > mean 87.42 μs (87.01 μs .. 87.88 μs) > std dev 1.481 μs (1.132 μs .. 1.953 μs) > variance introduced by outliers: 11% (moderately inflated) > > benchmarking tails/100000 > time 886.9 μs (882.9 μs .. 890.9 μs) > 1.000 R² (1.000 R² .. 1.000 R²) > mean 881.5 μs (878.1 μs .. 885.7 μs) > std dev 12.40 μs (9.598 μs .. 18.97 μs) > > benchmarking tails/1000000 > time 9.796 ms (9.757 ms .. 9.840 ms) > 1.000 R² (1.000 R² .. 1.000 R²) > mean 9.817 ms (9.791 ms .. 9.845 ms) > std dev 78.47 μs (60.63 μs .. 99.31 μs) > > > On 01-08-2019 10:25, Jaro Reinders wrote: >> If you fully evaluate the list produced by tails, then you're still >> spending O(n^2) time, because that is just the size of the produced >> list. But constructing the list and the memory taken by the list is >> O(n), because most of the lists are shared >> (https://wiki.haskell.org/Sharing). >> >> On 01-08-2019 04:45, Todd Wilson wrote: >>> It seems that, asymptotically, tails is O(n) while inits is O(n^2) in >>> both time and space (when fully evaluated) From will.yager at gmail.com Thu Aug 1 10:48:07 2019 From: will.yager at gmail.com (William Yager) Date: Thu, 1 Aug 2019 18:48:07 +0800 Subject: [Haskell-cafe] Performance best practices In-Reply-To: <8e0e3b02-be54-9d88-a30e-add0bb8d9b13@gmail.com> References: <204c1c06-4879-28ac-fd4b-abcdc3ea81b7@gmail.com> <8e0e3b02-be54-9d88-a30e-add0bb8d9b13@gmail.com> Message-ID: In high performance Haskell, you will often find yourself using sequential structures besides lists. For example, an unboxed vector implementation is over 100x faster than any of the proposed list implementations. Code: https://gist.github.com/wyager/45946f9f1531351468e4366b7ba168fa Benchmark result: https://gist.github.com/wyager/96e7876a4b170d83dca971dd152e475e GHC is very powerful, and can often do a surprisingly good job of optimizing away list allocations and such. However, in sharing-heavy applications like this (and if random indexing is helpful), Vectors can be much more efficient. On Thu, Aug 1, 2019 at 5:25 PM Jaro Reinders wrote: > I just realized seqTails and seqInits are unnecessary, seqList is enough. > > On 01-08-2019 11:04, Jaro Reinders wrote: > > Replying to myself, you can actually write an evaluation function that > > forces all values in the result of tails and inits in linear time: > > > > -- force the result of tails in linear time > > seqTails (x:xs) = x `deepseq` seqList xs > > seqTails [] = () > > > > -- force all the values in a list to whnf in linear time > > -- https://wiki.haskell.org/Weak_head_normal_form > > seqList (x:xs) = x `seq` seqList xs > > seqList [] = () > > > > -- force the result of inits in linear time > > seqInits xs = last xs `deepseq` seqList xs > > > > Try it in ghci with :sprint > > ( > https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html#ghci-cmd-:sprint > ): > > > > > let x = tails [1..3::Int] > > > :sprint x > > x = _ > > > seqTails x > > () > > > :sprint x > > x = [[1,2,3],[2,3],[3],[]] > > > > > let y = inits [1..3::Int] > > > :sprint y > > y = _ > > > seqInits y > > () > > > :sprint y > > y = [[],[1],[1,2],[1,2,3]] > > > > Using criterion you can see that it is actually linear time: > > > > main = defaultMain > > [ bgroup "inits" > > [ bench "1000" $ whnf (seqInits . inits) [1..1000 :: Int] > > , bench "10000" $ whnf (seqInits . inits) [1..10000 :: Int] > > , bench "100000" $ whnf (seqInits . inits) [1..100000 :: Int] > > , bench "1000000" $ whnf (seqInits . inits) [1..1000000 :: Int] > > ] > > , bgroup "tails" > > [ bench "1000" $ whnf (seqTails . tails) [1..1000 :: Int] > > , bench "10000" $ whnf (seqTails . tails) [1..10000 :: Int] > > , bench "100000" $ whnf (seqTails . tails) [1..100000 :: Int] > > , bench "1000000" $ whnf (seqTails . tails) [1..1000000 :: Int] > > ] > > ] > > > > > > benchmarking inits/1000 > > time 204.2 μs (203.2 μs .. 205.4 μs) > > 1.000 R² (1.000 R² .. 1.000 R²) > > mean 203.4 μs (202.8 μs .. 204.1 μs) > > std dev 2.163 μs (1.755 μs .. 2.664 μs) > > > > benchmarking inits/10000 > > time 3.127 ms (3.107 ms .. 3.148 ms) > > 1.000 R² (0.999 R² .. 1.000 R²) > > mean 3.105 ms (3.088 ms .. 3.118 ms) > > std dev 45.73 μs (32.97 μs .. 69.14 μs) > > > > benchmarking inits/100000 > > time 41.05 ms (39.11 ms .. 42.87 ms) > > 0.993 R² (0.988 R² .. 0.998 R²) > > mean 41.52 ms (40.62 ms .. 42.46 ms) > > std dev 1.912 ms (1.330 ms .. 2.930 ms) > > variance introduced by outliers: 12% (moderately inflated) > > > > benchmarking inits/1000000 > > time 423.0 ms (318.2 ms .. 535.5 ms) > > 0.991 R² (0.969 R² .. 1.000 R²) > > mean 459.1 ms (428.8 ms .. 505.2 ms) > > std dev 44.05 ms (10.06 ms .. 58.49 ms) > > variance introduced by outliers: 22% (moderately inflated) > > > > > > > > benchmarking tails/1000 > > time 8.811 μs (8.768 μs .. 8.873 μs) > > 1.000 R² (0.999 R² .. 1.000 R²) > > mean 8.874 μs (8.819 μs .. 8.963 μs) > > std dev 225.7 ns (168.4 ns .. 325.2 ns) > > variance introduced by outliers: 28% (moderately inflated) > > > > benchmarking tails/10000 > > time 87.21 μs (86.85 μs .. 87.79 μs) > > 1.000 R² (0.999 R² .. 1.000 R²) > > mean 87.42 μs (87.01 μs .. 87.88 μs) > > std dev 1.481 μs (1.132 μs .. 1.953 μs) > > variance introduced by outliers: 11% (moderately inflated) > > > > benchmarking tails/100000 > > time 886.9 μs (882.9 μs .. 890.9 μs) > > 1.000 R² (1.000 R² .. 1.000 R²) > > mean 881.5 μs (878.1 μs .. 885.7 μs) > > std dev 12.40 μs (9.598 μs .. 18.97 μs) > > > > benchmarking tails/1000000 > > time 9.796 ms (9.757 ms .. 9.840 ms) > > 1.000 R² (1.000 R² .. 1.000 R²) > > mean 9.817 ms (9.791 ms .. 9.845 ms) > > std dev 78.47 μs (60.63 μs .. 99.31 μs) > > > > > > On 01-08-2019 10:25, Jaro Reinders wrote: > >> If you fully evaluate the list produced by tails, then you're still > >> spending O(n^2) time, because that is just the size of the produced > >> list. But constructing the list and the memory taken by the list is > >> O(n), because most of the lists are shared > >> (https://wiki.haskell.org/Sharing). > >> > >> On 01-08-2019 04:45, Todd Wilson wrote: > >>> It seems that, asymptotically, tails is O(n) while inits is O(n^2) in > >>> both time and space (when fully evaluated) > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -------------- next part -------------- An HTML attachment was scrubbed... URL: From will.yager at gmail.com Thu Aug 1 10:54:40 2019 From: will.yager at gmail.com (William Yager) Date: Thu, 1 Aug 2019 18:54:40 +0800 Subject: [Haskell-cafe] Request for Comments In-Reply-To: References: Message-ID: This looks quite interesting, but I'm not sure how to read the examples. Could you perhaps explain some more how to traverse the matrix, and also provide a normal assembly program along with the matrix representation? On Thu, Aug 1, 2019 at 2:26 AM ibrahim Sagiroglu wrote: > Hello all, > > I have an attempt to present llvm assembly in [1]. Would you consider > taking some time to comment on it? > > [1] https://github.com/ibrahimsag/rw > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jaro.reinders at gmail.com Thu Aug 1 10:54:57 2019 From: jaro.reinders at gmail.com (Jaro Reinders) Date: Thu, 1 Aug 2019 12:54:57 +0200 Subject: [Haskell-cafe] Performance best practices In-Reply-To: References: <204c1c06-4879-28ac-fd4b-abcdc3ea81b7@gmail.com> <8e0e3b02-be54-9d88-a30e-add0bb8d9b13@gmail.com> Message-ID: <8eb5ad55-c049-6acf-8814-978c6b22ef46@gmail.com> To make the comparison more fair you should use the seqList function instead of nf for evaluation the list functions. Then the list version is actually faster (*sl is with my seqList function): benchmarking splits1 time 4.799 ms (4.751 ms .. 4.857 ms) 0.999 R² (0.998 R² .. 0.999 R²) mean 4.854 ms (4.821 ms .. 4.893 ms) std dev 111.0 μs (90.31 μs .. 136.2 μs) benchmarking splits2 time 12.18 ms (11.93 ms .. 12.53 ms) 0.995 R² (0.990 R² .. 0.999 R²) mean 12.82 ms (12.61 ms .. 13.04 ms) std dev 568.8 μs (514.4 μs .. 636.1 μs) variance introduced by outliers: 18% (moderately inflated) benchmarking splits3 time 4.118 ms (4.067 ms .. 4.164 ms) 0.999 R² (0.998 R² .. 0.999 R²) mean 4.186 ms (4.154 ms .. 4.229 ms) std dev 114.2 μs (89.12 μs .. 144.2 μs) variance introduced by outliers: 11% (moderately inflated) benchmarking splits1sl time 24.91 μs (24.78 μs .. 25.04 μs) 1.000 R² (1.000 R² .. 1.000 R²) mean 24.78 μs (24.67 μs .. 24.89 μs) std dev 378.3 ns (317.1 ns .. 466.5 ns) variance introduced by outliers: 11% (moderately inflated) benchmarking splits2sl time 8.903 ms (8.835 ms .. 8.962 ms) 1.000 R² (0.999 R² .. 1.000 R²) mean 8.877 ms (8.834 ms .. 8.924 ms) std dev 124.0 μs (104.2 μs .. 147.1 μs) benchmarking splits3sl time 11.54 μs (11.49 μs .. 11.58 μs) 1.000 R² (1.000 R² .. 1.000 R²) mean 11.59 μs (11.54 μs .. 11.64 μs) std dev 156.7 ns (127.7 ns .. 207.3 ns) benchmarking splits4 (boxed) time 1.903 ms (1.894 ms .. 1.910 ms) 1.000 R² (1.000 R² .. 1.000 R²) mean 1.908 ms (1.901 ms .. 1.915 ms) std dev 25.61 μs (20.81 μs .. 31.73 μs) benchmarking splits4 (unboxed) time 33.63 μs (33.51 μs .. 33.74 μs) 1.000 R² (1.000 R² .. 1.000 R²) mean 33.60 μs (33.46 μs .. 33.76 μs) std dev 493.7 ns (386.8 ns .. 622.1 ns) variance introduced by outliers: 10% (moderately inflated) On 01-08-2019 12:48, William Yager wrote: > In high performance Haskell, you will often find yourself using sequential > structures besides lists. For example, an unboxed vector implementation is > over 100x faster than any of the proposed list implementations. > > Code: https://gist.github.com/wyager/45946f9f1531351468e4366b7ba168fa > > Benchmark result: > https://gist.github.com/wyager/96e7876a4b170d83dca971dd152e475e > > GHC is very powerful, and can often do a surprisingly good job of > optimizing away list allocations and such. However, in sharing-heavy > applications like this (and if random indexing is helpful), Vectors can be > much more efficient. > > On Thu, Aug 1, 2019 at 5:25 PM Jaro Reinders > wrote: > >> I just realized seqTails and seqInits are unnecessary, seqList is enough. >> >> On 01-08-2019 11:04, Jaro Reinders wrote: >>> Replying to myself, you can actually write an evaluation function that >>> forces all values in the result of tails and inits in linear time: >>> >>> -- force the result of tails in linear time >>> seqTails (x:xs) = x `deepseq` seqList xs >>> seqTails [] = () >>> >>> -- force all the values in a list to whnf in linear time >>> -- https://wiki.haskell.org/Weak_head_normal_form >>> seqList (x:xs) = x `seq` seqList xs >>> seqList [] = () >>> >>> -- force the result of inits in linear time >>> seqInits xs = last xs `deepseq` seqList xs >>> >>> Try it in ghci with :sprint >>> ( >> https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html#ghci-cmd-:sprint >> ): >>> >>> > let x = tails [1..3::Int] >>> > :sprint x >>> x = _ >>> > seqTails x >>> () >>> > :sprint x >>> x = [[1,2,3],[2,3],[3],[]] >>> >>> > let y = inits [1..3::Int] >>> > :sprint y >>> y = _ >>> > seqInits y >>> () >>> > :sprint y >>> y = [[],[1],[1,2],[1,2,3]] >>> >>> Using criterion you can see that it is actually linear time: >>> >>> main = defaultMain >>> [ bgroup "inits" >>> [ bench "1000" $ whnf (seqInits . inits) [1..1000 :: Int] >>> , bench "10000" $ whnf (seqInits . inits) [1..10000 :: Int] >>> , bench "100000" $ whnf (seqInits . inits) [1..100000 :: Int] >>> , bench "1000000" $ whnf (seqInits . inits) [1..1000000 :: Int] >>> ] >>> , bgroup "tails" >>> [ bench "1000" $ whnf (seqTails . tails) [1..1000 :: Int] >>> , bench "10000" $ whnf (seqTails . tails) [1..10000 :: Int] >>> , bench "100000" $ whnf (seqTails . tails) [1..100000 :: Int] >>> , bench "1000000" $ whnf (seqTails . tails) [1..1000000 :: Int] >>> ] >>> ] >>> >>> >>> benchmarking inits/1000 >>> time 204.2 μs (203.2 μs .. 205.4 μs) >>> 1.000 R² (1.000 R² .. 1.000 R²) >>> mean 203.4 μs (202.8 μs .. 204.1 μs) >>> std dev 2.163 μs (1.755 μs .. 2.664 μs) >>> >>> benchmarking inits/10000 >>> time 3.127 ms (3.107 ms .. 3.148 ms) >>> 1.000 R² (0.999 R² .. 1.000 R²) >>> mean 3.105 ms (3.088 ms .. 3.118 ms) >>> std dev 45.73 μs (32.97 μs .. 69.14 μs) >>> >>> benchmarking inits/100000 >>> time 41.05 ms (39.11 ms .. 42.87 ms) >>> 0.993 R² (0.988 R² .. 0.998 R²) >>> mean 41.52 ms (40.62 ms .. 42.46 ms) >>> std dev 1.912 ms (1.330 ms .. 2.930 ms) >>> variance introduced by outliers: 12% (moderately inflated) >>> >>> benchmarking inits/1000000 >>> time 423.0 ms (318.2 ms .. 535.5 ms) >>> 0.991 R² (0.969 R² .. 1.000 R²) >>> mean 459.1 ms (428.8 ms .. 505.2 ms) >>> std dev 44.05 ms (10.06 ms .. 58.49 ms) >>> variance introduced by outliers: 22% (moderately inflated) >>> >>> >>> >>> benchmarking tails/1000 >>> time 8.811 μs (8.768 μs .. 8.873 μs) >>> 1.000 R² (0.999 R² .. 1.000 R²) >>> mean 8.874 μs (8.819 μs .. 8.963 μs) >>> std dev 225.7 ns (168.4 ns .. 325.2 ns) >>> variance introduced by outliers: 28% (moderately inflated) >>> >>> benchmarking tails/10000 >>> time 87.21 μs (86.85 μs .. 87.79 μs) >>> 1.000 R² (0.999 R² .. 1.000 R²) >>> mean 87.42 μs (87.01 μs .. 87.88 μs) >>> std dev 1.481 μs (1.132 μs .. 1.953 μs) >>> variance introduced by outliers: 11% (moderately inflated) >>> >>> benchmarking tails/100000 >>> time 886.9 μs (882.9 μs .. 890.9 μs) >>> 1.000 R² (1.000 R² .. 1.000 R²) >>> mean 881.5 μs (878.1 μs .. 885.7 μs) >>> std dev 12.40 μs (9.598 μs .. 18.97 μs) >>> >>> benchmarking tails/1000000 >>> time 9.796 ms (9.757 ms .. 9.840 ms) >>> 1.000 R² (1.000 R² .. 1.000 R²) >>> mean 9.817 ms (9.791 ms .. 9.845 ms) >>> std dev 78.47 μs (60.63 μs .. 99.31 μs) >>> >>> >>> On 01-08-2019 10:25, Jaro Reinders wrote: >>>> If you fully evaluate the list produced by tails, then you're still >>>> spending O(n^2) time, because that is just the size of the produced >>>> list. But constructing the list and the memory taken by the list is >>>> O(n), because most of the lists are shared >>>> (https://wiki.haskell.org/Sharing). >>>> >>>> On 01-08-2019 04:45, Todd Wilson wrote: >>>>> It seems that, asymptotically, tails is O(n) while inits is O(n^2) in >>>>> both time and space (when fully evaluated) >> _______________________________________________ >> Haskell-Cafe mailing list >> To (un)subscribe, modify options or view archives go to: >> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >> Only members subscribed via the mailman list are allowed to post. > From sag.ibrahim at gmail.com Thu Aug 1 11:05:09 2019 From: sag.ibrahim at gmail.com (ibrahim Sagiroglu) Date: Thu, 1 Aug 2019 14:05:09 +0300 Subject: [Haskell-cafe] Request for Comments In-Reply-To: References: Message-ID: assembly programs are in the ex folder. i should have mentioned that, thank you. Sequence of instructions are along the diagonal. register and label bindings are represented by other cells. maybe read it as a particular restriction on graph edges. You start from bottom, climb up to the top, the climbing was so interesting intuition to miss and also that the arguments are on the right. On 1 Aug 2019 Thu at 13:54 William Yager wrote: > This looks quite interesting, but I'm not sure how to read the examples. > Could you perhaps explain some more how to traverse the matrix, and also > provide a normal assembly program along with the matrix representation? > > On Thu, Aug 1, 2019 at 2:26 AM ibrahim Sagiroglu > wrote: > >> Hello all, >> >> I have an attempt to present llvm assembly in [1]. Would you consider >> taking some time to comment on it? >> >> [1] https://github.com/ibrahimsag/rw >> > _______________________________________________ >> Haskell-Cafe mailing list >> To (un)subscribe, modify options or view archives go to: >> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >> Only members subscribed via the mailman list are allowed to post. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From sag.ibrahim at gmail.com Thu Aug 1 14:56:12 2019 From: sag.ibrahim at gmail.com (ibrahim Sagiroglu) Date: Thu, 1 Aug 2019 17:56:12 +0300 Subject: [Haskell-cafe] Request for Comments In-Reply-To: References: Message-ID: Placed the code next to generated images in readme. Should not be further difficulties. I expect this to be useful for all sorts of ui needs. it is as intuitive as excel but much more. help me push it in the open. The idea is that a sparse adjacency matrix is just as friendly as any other graph layout. Especially when the diagonal cells strategically utilized. And exponentially more powerful since it can provide arbitrary details. On 1 Aug 2019 Thu at 14:05 ibrahim Sagiroglu wrote: > assembly programs are in the ex folder. i should have mentioned that, > thank you. > > Sequence of instructions are along the diagonal. register and label > bindings are represented by other cells. maybe read it as a particular > restriction on graph edges. > > You start from bottom, climb up to the top, the climbing was so > interesting intuition to miss and also that the arguments are on the right. > > On 1 Aug 2019 Thu at 13:54 William Yager wrote: > >> This looks quite interesting, but I'm not sure how to read the examples. >> Could you perhaps explain some more how to traverse the matrix, and also >> provide a normal assembly program along with the matrix representation? >> >> On Thu, Aug 1, 2019 at 2:26 AM ibrahim Sagiroglu >> wrote: >> >>> Hello all, >>> >>> I have an attempt to present llvm assembly in [1]. Would you consider >>> taking some time to comment on it? >>> >>> [1] https://github.com/ibrahimsag/rw >>> >> _______________________________________________ >>> Haskell-Cafe mailing list >>> To (un)subscribe, modify options or view archives go to: >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >>> Only members subscribed via the mailman list are allowed to post. >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From dsf at seereason.com Fri Aug 2 21:42:19 2019 From: dsf at seereason.com (David Fox) Date: Fri, 2 Aug 2019 14:42:19 -0700 Subject: [Haskell-cafe] ANN: To Kata Haskellen Evangelion In-Reply-To: References: Message-ID: I would say that the constraint means you can assume that the Eq instance exists when writing your Ord instance. If you try to write an Ord instance for a type with no Eq instance the compiler will complain, even though it might be possible to write the instance without using the Eq instance. I would mention that putting constraints on the class is often overkill, it may be better to put them on the individual instances as needed. But that may be too much information for a beginner. On Sun, Jul 28, 2019 at 8:51 AM David Fox wrote: > On page 39 you say > > A type can have Ord instance only when it has Eq instance, since if >> you want to compare items, you need a way to test if they are equal. > > > So from my reading of this you are saying that an Eq instance for a type > needs to be supplied before we are allowed to implement compare. However > it is easy to write a compare function that makes no use of the underlying > (==) function. Indeed, once you have done this you can turn around and > write a == b = compare a b == EQ. So I was wondering if you could clarify > the role of constraints in the class declaration. > > On Sun, Jul 28, 2019 at 2:38 AM Cosmia Fu wrote: > >> Hi everyone, >> >> Though some of you might already knows, I'm pleased to announce a new >> Haskell book, >> *To Kata Haskellen Evangelion*. >> Link: https://cosmius.bitbucket.io/tkhe/ >> I believe that it does not have to be hard to learn Haskell. >> >> I begun to write the book in 2017 December, and... to be honest, >> I don't know what to write now, though I still think it incomplete. >> It will probably not be updated for quite a while. >> So I decide to announce it earlier. >> >> I am not a native English speaker, so it might be not fluent or even with >> a lot of grammar mistakes. >> It would be very nice of you if you can tell me the mistakes in it, >> factual, technical or grammar. >> And also feel free to tell me if you want to read some topic in it. >> >> Thank you >> >> ---- >> >> Cosmia Fu >> _______________________________________________ >> Haskell-Cafe mailing list >> To (un)subscribe, modify options or view archives go to: >> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >> Only members subscribed via the mailman list are allowed to post. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ben.franksen at online.de Fri Aug 2 23:38:38 2019 From: ben.franksen at online.de (Benjamin Franksen) Date: Sat, 3 Aug 2019 01:38:38 +0200 Subject: [Haskell-cafe] instance Monoid a => Monad ((,) a) Message-ID: I wanted to define a simple Monad instance for (Bool,) as instance Monad ((,) Bool) where return x = (False, x) (True, x) >>= k = (True, snd (k x)) (False, x) >>= k = k x -- or: (b, x) >>= k = let (c, y) = k x in (b||c, y) The idea was to keep track of whether functions change their input value or not. To my astonishment I found that this definition overlaps with an existing one. GHC tells me x.hs:2:10: error: • No instance for (Monoid Bool) arising from the superclasses of an instance declaration • In the instance declaration for ‘Monad ((,) Bool)’ | 2 | instance Monad ((,) Bool) where | ^^^^^^^^^^^^^^^^ x.hs:2:10: error: • Overlapping instances for Monad ((,) Bool) arising from a use of ‘GHC.Base.$dm>>’ Matching instances: instance Monoid a => Monad ((,) a) -- Defined in ‘GHC.Base’ instance Monad ((,) Bool) -- Defined at x.hs:2:10 • In the expression: GHC.Base.$dm>> @((,) Bool) In an equation for ‘>>’: (>>) = GHC.Base.$dm>> @((,) Bool) In the instance declaration for ‘Monad ((,) Bool)’ | 2 | instance Monad ((,) Bool) where | ^^^^^^^^^^^^^^^^ [one more similar overlap error elided] But I could not find the instance Monoid a => Monad ((,) a) documented anywhere in the base package. Should I look harder? Or is this instance accidentally leaking from GHC.Base? Eventually, through some experimenting I found that if I replace Bool with Any, then the existing instance seems to do what I want. Cheers Ben From neil_mayhew at users.sourceforge.net Fri Aug 2 23:48:52 2019 From: neil_mayhew at users.sourceforge.net (Neil Mayhew) Date: Fri, 2 Aug 2019 17:48:52 -0600 Subject: [Haskell-cafe] instance Monoid a => Monad ((,) a) In-Reply-To: References: Message-ID: On 2019-08-02 5:38 p.m., Benjamin Franksen wrote: But I could not find the |instance Monoid a => Monad ((,) a)| documented anywhere in the base package. If you look at the list of instances under the definition of |Monad|, you’ll see |Monoid a => Monad ((,) a)| | /Since: 4.9.0.0/ in the list. Clicking on the |# Source| link takes you to the source of |GHC.Base|: |instance Monoid a => Monad ((,) a) where (u, a) >>= k = case k a of (v, b) -> (u <> v, b) | ​ -------------- next part -------------- An HTML attachment was scrubbed... URL: From ben.franksen at online.de Sat Aug 3 08:57:14 2019 From: ben.franksen at online.de (Ben Franksen) Date: Sat, 3 Aug 2019 10:57:14 +0200 Subject: [Haskell-cafe] instance Monoid a => Monad ((,) a) In-Reply-To: References: Message-ID: Am 03.08.19 um 01:48 schrieb Neil Mayhew: > On 2019-08-02 5:38 p.m., Benjamin Franksen wrote: > > But I could not find the > > |instance Monoid a => Monad ((,) a)| > > documented anywhere in the base package. > > If you look at the list of instances under the definition of |Monad|, > you’ll see |Monoid a => Monad ((,) a)| | /Since: 4.9.0.0/ in the list. > Clicking on the |# Source| link takes you to the source of |GHC.Base|: > > |instance Monoid a => Monad ((,) a) where (u, a) >>= k = case k a of (v, > b) -> (u <> v, b) | Thanks! No idea how/why I missed that. I have stared at that list for quite some time before sending my question, just couldn' see it... And yes, this is exactly the instance I had in mind (with Any instead of Bool). Cheers Ben From bertram.felgenhauer at googlemail.com Sun Aug 4 06:43:14 2019 From: bertram.felgenhauer at googlemail.com (Bertram Felgenhauer) Date: Sun, 4 Aug 2019 08:43:14 +0200 Subject: [Haskell-cafe] Performance best practices In-Reply-To: References: Message-ID: <20190804064314.GA3615@24f89f8c-e6a1-4e75-85ee-bb8a3743bb9f> Todd Wilson wrote: > For example, splits1 [1,2,3] is > [([],[1,2,3]),([1],[2,3]),([1,2],[3]),([1,2,3],[])]. Note that `inits` (and hence `splits`) on lists is inherently quadratic, because the resulting lists [1], [1,2], [1,2,3], and so on, cannot share any parts of their spines. The only way around this is to change the result, either the type (as suggested elsewhere in this list), or the result itself. A cute option is to produce reversed lists, which can be achieved by rinits = scanl (flip (:)) [] (so `rinits [1,2,3] = [[],[1],[2,1],[3,2,1]]`). This works on plain lists, and uses linear time and memory. (One can view this as changing the result type to a list of snoc lists. This fact can be expressed using a newtype wrapper or a custom list type if desired.) Cheers, Bertram From zhujinxuan at gmail.com Mon Aug 5 20:33:33 2019 From: zhujinxuan at gmail.com (Jinxuan Zhu) Date: Mon, 5 Aug 2019 16:33:33 -0400 Subject: [Haskell-cafe] instance Monoid a => Monad ((,) a) In-Reply-To: References: Message-ID: Hi, I think the error message says there is no Monoid for Bool. It is because Bool can be monoid by either || or && operations, which would lead to ambiguity if Bool is monoid by default. You can: 1. use Maybe Unit instead 2. (overkill) Define AndMonoid Bool newtype and use DeriveVia and coerce On Fri, Aug 2, 2019 at 7:39 PM Benjamin Franksen wrote: > I wanted to define a simple Monad instance for (Bool,) as > > instance Monad ((,) Bool) where > return x = (False, x) > (True, x) >>= k = (True, snd (k x)) > (False, x) >>= k = k x > -- or: (b, x) >>= k = let (c, y) = k x in (b||c, y) > > The idea was to keep track of whether functions change their input value > or not. > > To my astonishment I found that this definition overlaps with an > existing one. GHC tells me > > x.hs:2:10: error: > • No instance for (Monoid Bool) > arising from the superclasses of an instance declaration > • In the instance declaration for ‘Monad ((,) Bool)’ > | > 2 | instance Monad ((,) Bool) where > | ^^^^^^^^^^^^^^^^ > > x.hs:2:10: error: > • Overlapping instances for Monad ((,) Bool) > arising from a use of ‘GHC.Base.$dm>>’ > Matching instances: > instance Monoid a => Monad ((,) a) -- Defined in ‘GHC.Base’ > instance Monad ((,) Bool) -- Defined at x.hs:2:10 > • In the expression: GHC.Base.$dm>> @((,) Bool) > In an equation for ‘>>’: (>>) = GHC.Base.$dm>> @((,) Bool) > In the instance declaration for ‘Monad ((,) Bool)’ > | > 2 | instance Monad ((,) Bool) where > | ^^^^^^^^^^^^^^^^ > > [one more similar overlap error elided] > > But I could not find the > > instance Monoid a => Monad ((,) a) > > documented anywhere in the base package. Should I look harder? Or is > this instance accidentally leaking from GHC.Base? > > Eventually, through some experimenting I found that if I replace Bool > with Any, then the existing instance seems to do what I want. > > Cheers > Ben > > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Mon Aug 5 20:49:41 2019 From: david.feuer at gmail.com (David Feuer) Date: Mon, 5 Aug 2019 16:49:41 -0400 Subject: [Haskell-cafe] instance Monoid a => Monad ((,) a) In-Reply-To: References: Message-ID: Bool is also a monoid under xor. On Mon, Aug 5, 2019, 4:34 PM Jinxuan Zhu wrote: > Hi, I think the error message says there is no Monoid for Bool. It is > because Bool can be monoid by either || or && operations, which would lead > to ambiguity if Bool is monoid by default. > > You can: > 1. use Maybe Unit instead > 2. (overkill) Define AndMonoid Bool newtype and use DeriveVia and coerce > > > > On Fri, Aug 2, 2019 at 7:39 PM Benjamin Franksen > wrote: > >> I wanted to define a simple Monad instance for (Bool,) as >> >> instance Monad ((,) Bool) where >> return x = (False, x) >> (True, x) >>= k = (True, snd (k x)) >> (False, x) >>= k = k x >> -- or: (b, x) >>= k = let (c, y) = k x in (b||c, y) >> >> The idea was to keep track of whether functions change their input value >> or not. >> >> To my astonishment I found that this definition overlaps with an >> existing one. GHC tells me >> >> x.hs:2:10: error: >> • No instance for (Monoid Bool) >> arising from the superclasses of an instance declaration >> • In the instance declaration for ‘Monad ((,) Bool)’ >> | >> 2 | instance Monad ((,) Bool) where >> | ^^^^^^^^^^^^^^^^ >> >> x.hs:2:10: error: >> • Overlapping instances for Monad ((,) Bool) >> arising from a use of ‘GHC.Base.$dm>>’ >> Matching instances: >> instance Monoid a => Monad ((,) a) -- Defined in ‘GHC.Base’ >> instance Monad ((,) Bool) -- Defined at x.hs:2:10 >> • In the expression: GHC.Base.$dm>> @((,) Bool) >> In an equation for ‘>>’: (>>) = GHC.Base.$dm>> @((,) Bool) >> In the instance declaration for ‘Monad ((,) Bool)’ >> | >> 2 | instance Monad ((,) Bool) where >> | ^^^^^^^^^^^^^^^^ >> >> [one more similar overlap error elided] >> >> But I could not find the >> >> instance Monoid a => Monad ((,) a) >> >> documented anywhere in the base package. Should I look harder? Or is >> this instance accidentally leaking from GHC.Base? >> >> Eventually, through some experimenting I found that if I replace Bool >> with Any, then the existing instance seems to do what I want. >> >> Cheers >> Ben >> >> _______________________________________________ >> Haskell-Cafe mailing list >> To (un)subscribe, modify options or view archives go to: >> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >> Only members subscribed via the mailman list are allowed to post. > > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -------------- next part -------------- An HTML attachment was scrubbed... URL: From neil_mayhew at users.sourceforge.net Mon Aug 5 20:57:26 2019 From: neil_mayhew at users.sourceforge.net (Neil Mayhew) Date: Mon, 5 Aug 2019 14:57:26 -0600 Subject: [Haskell-cafe] instance Monoid a => Monad ((,) a) In-Reply-To: References: Message-ID: <942a6ac0-971d-9099-adec-fafe95c73cfd@users.sourceforge.net> On 2019-08-05 2:33 p.m., Jinxuan Zhu wrote: … Bool can be monoid by either || or && operations, which would lead to ambiguity if Bool is monoid by default. You can: 1. use Maybe Unit instead 2. (overkill) Define AndMonoid Bool newtype and use DeriveVia and coerce |Data.Monoid| from |base| already has |Any| and |All| for this. ​ -------------- next part -------------- An HTML attachment was scrubbed... URL: From oleg.grenrus at iki.fi Tue Aug 6 09:03:55 2019 From: oleg.grenrus at iki.fi (Oleg Grenrus) Date: Tue, 6 Aug 2019 12:03:55 +0300 Subject: [Haskell-cafe] instance Monoid a => Monad ((,) a) In-Reply-To: References: Message-ID: There are All and Any Monoids in Data.Monoid Sent from my iPhone > On 5 Aug 2019, at 23.33, Jinxuan Zhu wrote: > > Hi, I think the error message says there is no Monoid for Bool. It is because Bool can be monoid by either || or && operations, which would lead to ambiguity if Bool is monoid by default. > > You can: > 1. use Maybe Unit instead > 2. (overkill) Define AndMonoid Bool newtype and use DeriveVia and coerce > > > >> On Fri, Aug 2, 2019 at 7:39 PM Benjamin Franksen wrote: >> I wanted to define a simple Monad instance for (Bool,) as >> >> instance Monad ((,) Bool) where >> return x = (False, x) >> (True, x) >>= k = (True, snd (k x)) >> (False, x) >>= k = k x >> -- or: (b, x) >>= k = let (c, y) = k x in (b||c, y) >> >> The idea was to keep track of whether functions change their input value >> or not. >> >> To my astonishment I found that this definition overlaps with an >> existing one. GHC tells me >> >> x.hs:2:10: error: >> • No instance for (Monoid Bool) >> arising from the superclasses of an instance declaration >> • In the instance declaration for ‘Monad ((,) Bool)’ >> | >> 2 | instance Monad ((,) Bool) where >> | ^^^^^^^^^^^^^^^^ >> >> x.hs:2:10: error: >> • Overlapping instances for Monad ((,) Bool) >> arising from a use of ‘GHC.Base.$dm>>’ >> Matching instances: >> instance Monoid a => Monad ((,) a) -- Defined in ‘GHC.Base’ >> instance Monad ((,) Bool) -- Defined at x.hs:2:10 >> • In the expression: GHC.Base.$dm>> @((,) Bool) >> In an equation for ‘>>’: (>>) = GHC.Base.$dm>> @((,) Bool) >> In the instance declaration for ‘Monad ((,) Bool)’ >> | >> 2 | instance Monad ((,) Bool) where >> | ^^^^^^^^^^^^^^^^ >> >> [one more similar overlap error elided] >> >> But I could not find the >> >> instance Monoid a => Monad ((,) a) >> >> documented anywhere in the base package. Should I look harder? Or is >> this instance accidentally leaking from GHC.Base? >> >> Eventually, through some experimenting I found that if I replace Bool >> with Any, then the existing instance seems to do what I want. >> >> Cheers >> Ben >> >> _______________________________________________ >> Haskell-Cafe mailing list >> To (un)subscribe, modify options or view archives go to: >> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >> Only members subscribed via the mailman list are allowed to post. > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -------------- next part -------------- An HTML attachment was scrubbed... URL: From tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk Tue Aug 6 12:15:01 2019 From: tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk (Tom Ellis) Date: Tue, 6 Aug 2019 13:15:01 +0100 Subject: [Haskell-cafe] instance Monoid a => Monad ((,) a) In-Reply-To: References: Message-ID: <20190806121501.ckkvujdqwd7d5qta@weber> When this question came up the other day I started to wonder how many boolean operators are monoidal. I wrote a program to check. There are eight associative operators (i.e. that give rise to semigroups). They are const True or const flip const xnor and xor const False Only four of these have an identity (i.e. give rise to monoids). They are or xnor and xor Tom > putStrLn showMonoids Semigroups TT=T TF=T FT=T FF=T TT=T TF=T FT=T FF=F TT=T TF=T FT=F FF=F TT=T TF=F FT=T FF=F TT=T TF=F FT=F FF=T TT=T TF=F FT=F FF=F TT=F TF=T FT=T FF=F TT=F TF=F FT=F FF=F Monoids TT=T TF=T FT=T FF=F TT=T TF=F FT=F FF=T TT=T TF=F FT=F FF=F TT=F TF=T FT=T FF=F allOfThem :: [Bool] allOfThem = [True, False] binops :: [Bool -> Bool -> Bool] binops = do tt <- allOfThem tf <- allOfThem ft <- allOfThem ff <- allOfThem let f True True = tt f True False = tf f False True = ft f False False = ff pure f associative :: (Bool -> Bool -> Bool) -> Bool associative (.*) = and $ do x <- allOfThem y <- allOfThem z <- allOfThem pure (x .* (y .* z) == (x .* y) .* z) identity :: (Bool -> Bool -> Bool) -> Bool identity (.*) = or $ do i <- allOfThem return (and $ do x <- allOfThem [x .* i == x, i .* x == x]) semigroups :: [Bool -> Bool -> Bool] semigroups = filter associative binops monoids :: [Bool -> Bool -> Bool] monoids = filter identity semigroups showBool :: Bool -> String showBool True = "T" showBool False = "F" showBinop :: (Bool -> Bool -> Bool) -> String showBinop (.*) = unwords $ do x <- allOfThem y <- allOfThem pure (showBool x ++ showBool y ++ "=" ++ showBool (x .* y)) showMonoids :: String showMonoids = (unlines . concat) [ ["Semigroups"] , map showBinop semigroups , ["Monoids"] , map showBinop monoids ] On Mon, Aug 05, 2019 at 04:49:41PM -0400, David Feuer wrote: > Bool is also a monoid under xor. > > On Mon, Aug 5, 2019, 4:34 PM Jinxuan Zhu wrote: > > > Hi, I think the error message says there is no Monoid for Bool. It is > > because Bool can be monoid by either || or && operations, which would lead > > to ambiguity if Bool is monoid by default. > > > > You can: > > 1. use Maybe Unit instead > > 2. (overkill) Define AndMonoid Bool newtype and use DeriveVia and coerce > > > > On Fri, Aug 2, 2019 at 7:39 PM Benjamin Franksen > > wrote: > > > >> I wanted to define a simple Monad instance for (Bool,) as > >> > >> instance Monad ((,) Bool) where > >> return x = (False, x) > >> (True, x) >>= k = (True, snd (k x)) > >> (False, x) >>= k = k x > >> -- or: (b, x) >>= k = let (c, y) = k x in (b||c, y) > >> > >> The idea was to keep track of whether functions change their input value > >> or not. > >> > >> To my astonishment I found that this definition overlaps with an > >> existing one. GHC tells me > >> > >> x.hs:2:10: error: > >> • No instance for (Monoid Bool) > >> arising from the superclasses of an instance declaration > >> • In the instance declaration for ‘Monad ((,) Bool)’ > >> | > >> 2 | instance Monad ((,) Bool) where > >> | ^^^^^^^^^^^^^^^^ > >> > >> x.hs:2:10: error: > >> • Overlapping instances for Monad ((,) Bool) > >> arising from a use of ‘GHC.Base.$dm>>’ > >> Matching instances: > >> instance Monoid a => Monad ((,) a) -- Defined in ‘GHC.Base’ > >> instance Monad ((,) Bool) -- Defined at x.hs:2:10 > >> • In the expression: GHC.Base.$dm>> @((,) Bool) > >> In an equation for ‘>>’: (>>) = GHC.Base.$dm>> @((,) Bool) > >> In the instance declaration for ‘Monad ((,) Bool)’ > >> | > >> 2 | instance Monad ((,) Bool) where > >> | ^^^^^^^^^^^^^^^^ > >> > >> [one more similar overlap error elided] > >> > >> But I could not find the > >> > >> instance Monoid a => Monad ((,) a) > >> > >> documented anywhere in the base package. Should I look harder? Or is > >> this instance accidentally leaking from GHC.Base? > >> > >> Eventually, through some experimenting I found that if I replace Bool > >> with Any, then the existing instance seems to do what I want. From hjgtuyl at chello.nl Wed Aug 7 00:11:42 2019 From: hjgtuyl at chello.nl (Henk-Jan van Tuyl) Date: Wed, 07 Aug 2019 02:11:42 +0200 Subject: [Haskell-cafe] cabal: Could not resolve dependencies Message-ID: L.S., I am trying to compile wxHaskell with GHC 8.8.0.20190721 and I get the following messages from cabal-install: > cabal new-build all --disable-documentation Resolving dependencies... cabal: Could not resolve dependencies: [__0] trying: samplesContrib-0.93.0.0 (user goal) [__1] trying: base-4.13.0.0/installed-4.1... (dependency of samplesContrib) [__2] trying: wxcore-0.93.0.0 (user goal) [__3] next goal: wxcore:setup.Cabal (dependency of wxcore) [__3] rejecting: wxcore:setup.Cabal-3.0.0.0/installed-3.0... (constraint from maximum version of Cabal used by Setup.hs requires <2.6 [...] What does this mean, how do I solve it? (There is a Setup.hs in package wxcore, but does it have its own Cabal file?) > cabal --version cabal-install version 2.4.1.0 compiled using version 2.4.1.0 of the Cabal library Regards, Henk-Jan van Tuyl -- Message from Stanford University: Folding at home What if you could share your unused computer power to help find a cure? In just 5 minutes you can join the world's biggest networked computer and get us closer sooner. Watch the video. http://foldingathome.stanford.edu/ -- http://members.chello.nl/hjgtuyl/tourdemonad.html Haskell programming -- From vamchale at gmail.com Wed Aug 7 02:03:23 2019 From: vamchale at gmail.com (Vanessa McHale) Date: Tue, 6 Aug 2019 21:03:23 -0500 Subject: [Haskell-cafe] cabal: Could not resolve dependencies In-Reply-To: References: Message-ID: Is there a reason you're using GHC 8.8.1? This means that wxcore uses a custom setup, and that custom setup requires Cabal <2.6. But you can't use Cabal 2.4 because that requires base <4.13 Cheers, Vanessa McHale On 8/6/19 7:11 PM, Henk-Jan van Tuyl wrote: > > L.S., > > I am trying to compile wxHaskell with GHC 8.8.0.20190721 and I get the > following messages from cabal-install: > >> cabal new-build all --disable-documentation > Resolving dependencies... > cabal: Could not resolve dependencies: > [__0] trying: samplesContrib-0.93.0.0 (user goal) > [__1] trying: base-4.13.0.0/installed-4.1... (dependency of > samplesContrib) > [__2] trying: wxcore-0.93.0.0 (user goal) > [__3] next goal: wxcore:setup.Cabal (dependency of wxcore) > [__3] rejecting: wxcore:setup.Cabal-3.0.0.0/installed-3.0... > (constraint from > maximum version of Cabal used by Setup.hs requires <2.6 > [...] > > What does this mean, how do I solve it? > (There is a Setup.hs in package wxcore, but does it have its own Cabal > file?) > >> cabal --version > cabal-install version 2.4.1.0 > compiled using version 2.4.1.0 of the Cabal library > > Regards, > Henk-Jan van Tuyl > > -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 659 bytes Desc: OpenPGP digital signature URL: From hilco.wijbenga at gmail.com Wed Aug 7 03:28:34 2019 From: hilco.wijbenga at gmail.com (Hilco Wijbenga) Date: Tue, 6 Aug 2019 20:28:34 -0700 Subject: [Haskell-cafe] Evaluating an AST with GADTs (and Type Families?) Message-ID: Hi all, I'm trying to implement an evaluator with GADTs. This is about as far as I've gotten: https://pastebin.com/XjWBzgw7 . data Value = ValueBool Bool | ValueText String | ValueObject (Map String Value) data Expr t where ExprBool :: Bool -> Expr Bool ExprBoolOr :: Expr Bool -> Expr Bool -> Expr Bool ExprText :: String -> Expr String ExprTextAppend :: Expr String -> Expr String -> Expr String ExprObject :: Map String Value -> String -> Expr Value eval :: Expr t -> t eval (ExprBool value) = value eval (ExprBoolOr lft rgt) = eval lft || eval rgt eval (ExprText value) = value eval (ExprTextAppend lft rgt) = eval lft <> eval rgt eval (ExprObject map fieldName) = map ! fieldName Note that the Value data type was just an attempt and not (necessarily) what I'm looking for. And I'm ignoring all error handling for the moment to keep the example small. This compiles but obviously the object type is completely separate from the Expr Bool and Expr String types. Apparently, Type Familiies might help here? I could not find anything relevant that really explained it. I've been thinking about changing ExprObject to something like ExprObjectBool :: Map String Value -> String -> Expr Bool ExprObjectString :: Map String Value -> String -> Expr String ExprObjectObject :: Map String Value -> String -> Expr ??? but I can't figure out what ??? would be. And this would seem to explode if I add more "primitive" types, especially if I want to support lists and maps as well. (Maps and objects are very similar but not the same.) How would I go about making the object type useful here? Or should I go back to plain "Expr" and just error out when trying to, e.g., "or" 2 Strings? Cheers, Hilco From 78emil at gmail.com Wed Aug 7 08:35:08 2019 From: 78emil at gmail.com (Emil Axelsson) Date: Wed, 7 Aug 2019 10:35:08 +0200 Subject: [Haskell-cafe] Evaluating an AST with GADTs (and Type Families?) In-Reply-To: References: Message-ID: Hi! I would just skip the `Value` type and go with this     type Object = Map String     data Expr t where         ExprBool :: Bool -> Expr Bool         ExprBoolOr :: Expr Bool -> Expr Bool -> Expr Bool         ExprText :: String -> Expr String         ExprTextAppend :: Expr String -> Expr String -> Expr String         ExprObject :: Object (Expr t) -> Expr (Object t)         ExprLookup :: Expr (Object t) -> String -> Expr t     eval :: Expr t -> t     eval (ExprBool value) = value     eval (ExprBoolOr lft rgt) = eval lft || eval rgt     eval (ExprText value) = value     eval (ExprTextAppend lft rgt) = eval lft <> eval rgt     eval (ExprObject map) = eval <$> map     eval (ExprLookup map fieldName) = eval map ! fieldName `ExprObject` constructs an object expression from a mapping that has expressions in the range. `ExprLookup` looks up a field name from an object expression. This is more general, because it lets you have expressions of arbitrary type in objects. But it gets harder if you need to restrict the types that can appear in objects. / Emil Den 2019-08-07 kl. 05:28, skrev Hilco Wijbenga: > Hi all, > > I'm trying to implement an evaluator with GADTs. This is about as far > as I've gotten: https://pastebin.com/XjWBzgw7 . > > data Value > = ValueBool Bool > | ValueText String > | ValueObject (Map String Value) > > data Expr t where > ExprBool :: Bool -> Expr Bool > ExprBoolOr :: Expr Bool -> Expr Bool -> Expr Bool > ExprText :: String -> Expr String > ExprTextAppend :: Expr String -> Expr String -> Expr String > ExprObject :: Map String Value -> String -> Expr Value > > eval :: Expr t -> t > eval (ExprBool value) = value > eval (ExprBoolOr lft rgt) = eval lft || eval rgt > eval (ExprText value) = value > eval (ExprTextAppend lft rgt) = eval lft <> eval rgt > eval (ExprObject map fieldName) = map ! fieldName > > Note that the Value data type was just an attempt and not > (necessarily) what I'm looking for. And I'm ignoring all error > handling for the moment to keep the example small. > > This compiles but obviously the object type is completely separate > from the Expr Bool and Expr String types. Apparently, Type Familiies > might help here? I could not find anything relevant that really > explained it. > > I've been thinking about changing ExprObject to something like > > ExprObjectBool :: Map String Value -> String -> Expr Bool > ExprObjectString :: Map String Value -> String -> Expr String > ExprObjectObject :: Map String Value -> String -> Expr ??? > > but I can't figure out what ??? would be. And this would seem to > explode if I add more "primitive" types, especially if I want to > support lists and maps as well. (Maps and objects are very similar but > not the same.) > > How would I go about making the object type useful here? Or should I > go back to plain "Expr" and just error out when trying to, e.g., "or" > 2 Strings? > > Cheers, > Hilco > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. From kolar at fit.vut.cz Wed Aug 7 09:52:35 2019 From: kolar at fit.vut.cz (=?utf-8?B?RHXFoWFuIEtvbMOhxZk=?=) Date: Wed, 07 Aug 2019 11:52:35 +0200 Subject: [Haskell-cafe] Ambiguous types Message-ID: <2162795.o9Qe6PU3hX@pckolar> Dear Café, I'm trying to solve a couple of examples and exercises just for me. I've come to the point, when I'm trying working code manipulating lists rewrite to work on Foldable (etc.). Nevertheless, I must be doing some mistake, overlooking something, as simple code like this: chkDup [] = False chkDup (0:ns) = chkDup ns chkDup (n:ns) = elem n ns || chkDup ns which works fine, type-checks, can be used within other code, I'm trying to replace with more generic, but probably less efficient and wrong code: chkDup ns = fst $ foldr f (False,mempty) ns where f _ res@(True,_) = res f v res@(_,vs) = if v==0 then (False, vs) else (elem v vs, pure v <> vs) which does not even type-check. Nevertheless, the error message is not too helpful, searching the Internet just confirms it's wrong and that adding AllowAmbiguousTypes would not work. The error message is: helper.hs:49:1: error: • Could not deduce (Foldable f0) from the context: (Eq a, Num a, Foldable t, Foldable f, Applicative f, Monoid (f a)) bound by the inferred type for ‘chkDup’: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, Foldable t, Foldable f, Applicative f, Monoid (f a)) => t a -> Bool at helper.hs:(49,1)-(53,80) The type variable ‘f0’ is ambiguous • In the ambiguity check for the inferred type for ‘chkDup’ To defer the ambiguity check to use sites, enable AllowAmbiguousTypes When checking the inferred type chkDup :: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, Foldable t, Foldable f, Applicative f, Monoid (f a)) => t a -> Bool | 49 | chkDup ns = | ^^^^^^^^^^^... So is there a nicer and working way, how to change my simple example? Is there a way, how to make it compile? Or is it useless to do that, original function is just fine... Best regards, Dušan -------------- next part -------------- An HTML attachment was scrubbed... URL: From paolo.veronelli at gmail.com Wed Aug 7 11:05:39 2019 From: paolo.veronelli at gmail.com (Paolino) Date: Wed, 7 Aug 2019 13:05:39 +0200 Subject: [Haskell-cafe] Ambiguous types In-Reply-To: <2162795.o9Qe6PU3hX@pckolar> References: <2162795.o9Qe6PU3hX@pckolar> Message-ID: So about the type error, the second element of the tuple has no defined type. You can fix it substituting (pure v) with [v] if you want a list there. Also - chkDup ns = any (`elem` ns) - use Set.member to reduce complexity Best On Wed, 7 Aug 2019 at 11:53, Dušan Kolář wrote: > Dear Café, > > > > I'm trying to solve a couple of examples and exercises just for me. I've > come to the point, when I'm trying working code manipulating lists rewrite > to work on Foldable (etc.). > > > > Nevertheless, I must be doing some mistake, overlooking something, as > simple code like this: > > > > chkDup [] = False > > chkDup (0:ns) = chkDup ns > > chkDup (n:ns) = elem n ns || chkDup ns > > > > which works fine, type-checks, can be used within other code, I'm trying > to replace with more generic, but probably less efficient and wrong code: > > > > chkDup ns = fst $ foldr f (False,mempty) ns > > where > > f _ res@(True,_) = res > > f v res@(_,vs) = if v==0 then (False, vs) else (elem v vs, pure v <> vs) > > > > which does not even type-check. > > > > Nevertheless, the error message is not too helpful, searching the Internet > just confirms it's wrong and that adding AllowAmbiguousTypes would not > work. The error message is: > > > > helper.hs:49:1: error: > > • Could not deduce (Foldable f0) > > from the context: (Eq a, Num a, Foldable t, Foldable f, > > Applicative f, Monoid (f a)) > > bound by the inferred type for ‘chkDup’: > > forall a (t :: * -> *) (f :: * -> *). > > (Eq a, Num a, Foldable t, Foldable f, Applicative f, > > Monoid (f a)) => > > t a -> Bool > > at helper.hs:(49,1)-(53,80) > > The type variable ‘f0’ is ambiguous > > • In the ambiguity check for the inferred type for ‘chkDup’ > > To defer the ambiguity check to use sites, enable AllowAmbiguousTypes > > When checking the inferred type > > chkDup :: forall a (t :: * -> *) (f :: * -> *). > > (Eq a, Num a, Foldable t, Foldable f, Applicative f, > > Monoid (f a)) => > > t a -> Bool > > | > > 49 | chkDup ns = > > | ^^^^^^^^^^^... > > > > > > So is there a nicer and working way, how to change my simple example? Is > there a way, how to make it compile? Or is it useless to do that, original > function is just fine... > > > > Best regards, > > Dušan > > > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -- Paolo Veronelli (paolo.veronelli at gmail.com) *Functional developer @ global.de * -------------- next part -------------- An HTML attachment was scrubbed... URL: From paolo.veronelli at gmail.com Wed Aug 7 11:13:32 2019 From: paolo.veronelli at gmail.com (Paolino) Date: Wed, 7 Aug 2019 13:13:32 +0200 Subject: [Haskell-cafe] Ambiguous types In-Reply-To: References: <2162795.o9Qe6PU3hX@pckolar> Message-ID: Pardon, delete my code. I rushed the answer without reading carefully, my bad. On Wed, 7 Aug 2019 at 13:05, Paolino wrote: > So about the type error, the second element of the tuple has no defined > type. You can fix it substituting (pure v) with [v] if you want a list > there. > > Also > > - chkDup ns = any (`elem` ns) > - use Set.member to reduce complexity > > Best > > On Wed, 7 Aug 2019 at 11:53, Dušan Kolář wrote: > >> Dear Café, >> >> >> >> I'm trying to solve a couple of examples and exercises just for me. I've >> come to the point, when I'm trying working code manipulating lists rewrite >> to work on Foldable (etc.). >> >> >> >> Nevertheless, I must be doing some mistake, overlooking something, as >> simple code like this: >> >> >> >> chkDup [] = False >> >> chkDup (0:ns) = chkDup ns >> >> chkDup (n:ns) = elem n ns || chkDup ns >> >> >> >> which works fine, type-checks, can be used within other code, I'm trying >> to replace with more generic, but probably less efficient and wrong code: >> >> >> >> chkDup ns = fst $ foldr f (False,mempty) ns >> >> where >> >> f _ res@(True,_) = res >> >> f v res@(_,vs) = if v==0 then (False, vs) else (elem v vs, pure v <> vs) >> >> >> >> which does not even type-check. >> >> >> >> Nevertheless, the error message is not too helpful, searching the >> Internet just confirms it's wrong and that adding AllowAmbiguousTypes would >> not work. The error message is: >> >> >> >> helper.hs:49:1: error: >> >> • Could not deduce (Foldable f0) >> >> from the context: (Eq a, Num a, Foldable t, Foldable f, >> >> Applicative f, Monoid (f a)) >> >> bound by the inferred type for ‘chkDup’: >> >> forall a (t :: * -> *) (f :: * -> *). >> >> (Eq a, Num a, Foldable t, Foldable f, Applicative f, >> >> Monoid (f a)) => >> >> t a -> Bool >> >> at helper.hs:(49,1)-(53,80) >> >> The type variable ‘f0’ is ambiguous >> >> • In the ambiguity check for the inferred type for ‘chkDup’ >> >> To defer the ambiguity check to use sites, enable AllowAmbiguousTypes >> >> When checking the inferred type >> >> chkDup :: forall a (t :: * -> *) (f :: * -> *). >> >> (Eq a, Num a, Foldable t, Foldable f, Applicative f, >> >> Monoid (f a)) => >> >> t a -> Bool >> >> | >> >> 49 | chkDup ns = >> >> | ^^^^^^^^^^^... >> >> >> >> >> >> So is there a nicer and working way, how to change my simple example? Is >> there a way, how to make it compile? Or is it useless to do that, original >> function is just fine... >> >> >> >> Best regards, >> >> Dušan >> >> >> _______________________________________________ >> Haskell-Cafe mailing list >> To (un)subscribe, modify options or view archives go to: >> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >> Only members subscribed via the mailman list are allowed to post. > > > > -- > > Paolo Veronelli (paolo.veronelli at gmail.com) > > > *Functional developer @ global.de * > > -- Paolo Veronelli (paolo.veronelli at gmail.com) *Functional developer @ global.de * -------------- next part -------------- An HTML attachment was scrubbed... URL: From juan.casanova at ed.ac.uk Wed Aug 7 11:17:27 2019 From: juan.casanova at ed.ac.uk (Juan Casanova) Date: Wed, 07 Aug 2019 12:17:27 +0100 Subject: [Haskell-cafe] Ambiguous types In-Reply-To: References: <2162795.o9Qe6PU3hX@pckolar> Message-ID: <20190807121727.18661n6493o30sis@www.staffmail.ed.ac.uk> To build up on Paolino's answer, and maybe, if you're like me, give you a better intuition as to why your code was incorrect, but leading to essentially the same answer he gave. First, you didn't provide us with the type signatures for chkDup and f, but I worked with the following ones to start with: chkDup :: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, Foldable t, Foldable f, Applicative f, Monoid (f a)) => t a -> Bool f :: (Num a, Foldable t, Semigroup (t a), Applicative t, Eq a) => a -> (Bool, t a) -> (Bool, t a) This gives me the same error you get even if I define chkDup _ = undefined. The problem is that you are providing class constraints for the type f, which does not appear at all in the signature of the function (t a -> Bool), and this makes the typechecker get super confused. Now, I know why you thought this was necessary: precisely because of what Paolino pointed out: mempty has an undefined type, and you tried to fix this by saying "This mempty is of type f, which I don't care for the type, just that it is a Semigroup and Applicative". But this is a mistake. So, if you just remove the f altogether from the class constraints of the chkDup type signature, and leave it like this: chkDup :: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, Foldable t) => t a -> Bool You still get an error, but now you get the actual error message that you're looking for: "Could not deduce Foldable t0 arising from a use of f". The right way to fix this is how Paolino said: Specify what Foldable you're going to use (recommended: list) (so, use [] instead of mempty). The point is, since the type f is not part of the input NOR the output of the function chkDup, and instead it is just an internal tool that you use to compute chkDup, there's no reason to want to be generic about it, there's no advantage in that. The advantage in genericity using typeclasses is: 1. If it's in the input, you allow the user of the function to provide you with any type that fulfills the class. 2. You make it very clear that everything you do with that parameter is related to its typeclass instance, as there is no way to inspect the actual type. 3. If it's in the output, you don't let users of the function make any assumption of what that type might look like, other than its typeclass instance. But in an internal tool that doesn't come from outside and isn't output by your function, there's no reason to be generic, just use lists. The only reason I could see being argued for wanting to be generic would be if you'd like the user to provide you with hints as to how to compute the function so that it's more efficient. If you really want to go that far, I think there's other ways to do that, that I haven't thought of right now. All in all, the following code works: chkDup :: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, Foldable t) => t a -> Bool chkDup ns = fst $ foldr f (False,[]) ns f :: (Num a, Foldable t, Semigroup (t a), Applicative t, Eq a) => a -> (Bool, t a) -> (Bool, t a) f _ res@(True,_) = res f v res@(_,vs) = if v==0 then (False, vs) else (elem v vs, pure v <> vs) I hope you found that useful. Juan. Quoting Paolino on Wed, 7 Aug 2019 13:05:39 +0200: > So about the type error, the second element of the tuple has no defined > type. You can fix it substituting (pure v) with [v] if you want a list > there. > > Also > > - chkDup ns = any (`elem` ns) > - use Set.member to reduce complexity > > Best > > On Wed, 7 Aug 2019 at 11:53, Dušan Kolář wrote: > >> Dear Café, >> >> >> >> I'm trying to solve a couple of examples and exercises just for me. I've >> come to the point, when I'm trying working code manipulating lists rewrite >> to work on Foldable (etc.). >> >> >> >> Nevertheless, I must be doing some mistake, overlooking something, as >> simple code like this: >> >> >> >> chkDup [] = False >> >> chkDup (0:ns) = chkDup ns >> >> chkDup (n:ns) = elem n ns || chkDup ns >> >> >> >> which works fine, type-checks, can be used within other code, I'm trying >> to replace with more generic, but probably less efficient and wrong code: >> >> >> >> chkDup ns = fst $ foldr f (False,mempty) ns >> >> where >> >> f _ res@(True,_) = res >> >> f v res@(_,vs) = if v==0 then (False, vs) else (elem v vs, pure v <> vs) >> >> >> >> which does not even type-check. >> >> >> >> Nevertheless, the error message is not too helpful, searching the Internet >> just confirms it's wrong and that adding AllowAmbiguousTypes would not >> work. The error message is: >> >> >> >> helper.hs:49:1: error: >> >> • Could not deduce (Foldable f0) >> >> from the context: (Eq a, Num a, Foldable t, Foldable f, >> >> Applicative f, Monoid (f a)) >> >> bound by the inferred type for ‘chkDup’: >> >> forall a (t :: * -> *) (f :: * -> *). >> >> (Eq a, Num a, Foldable t, Foldable f, Applicative f, >> >> Monoid (f a)) => >> >> t a -> Bool >> >> at helper.hs:(49,1)-(53,80) >> >> The type variable ‘f0’ is ambiguous >> >> • In the ambiguity check for the inferred type for ‘chkDup’ >> >> To defer the ambiguity check to use sites, enable AllowAmbiguousTypes >> >> When checking the inferred type >> >> chkDup :: forall a (t :: * -> *) (f :: * -> *). >> >> (Eq a, Num a, Foldable t, Foldable f, Applicative f, >> >> Monoid (f a)) => >> >> t a -> Bool >> >> | >> >> 49 | chkDup ns = >> >> | ^^^^^^^^^^^... >> >> >> >> >> >> So is there a nicer and working way, how to change my simple example? Is >> there a way, how to make it compile? Or is it useless to do that, original >> function is just fine... >> >> >> >> Best regards, >> >> Dušan >> >> >> _______________________________________________ >> Haskell-Cafe mailing list >> To (un)subscribe, modify options or view archives go to: >> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >> Only members subscribed via the mailman list are allowed to post. > > > > -- > > Paolo Veronelli (paolo.veronelli at gmail.com) > > > *Functional developer @ global.de * > -- The University of Edinburgh is a charitable body, registered in Scotland, with registration number SC005336. From juan.casanova at ed.ac.uk Wed Aug 7 11:21:27 2019 From: juan.casanova at ed.ac.uk (Juan Casanova) Date: Wed, 07 Aug 2019 12:21:27 +0100 Subject: [Haskell-cafe] Ambiguous types In-Reply-To: <20190807121727.18661n6493o30sis@www.staffmail.ed.ac.uk> References: <2162795.o9Qe6PU3hX@pckolar> <20190807121727.18661n6493o30sis@www.staffmail.ed.ac.uk> Message-ID: <20190807122127.14952dhisipgjr6s@www.staffmail.ed.ac.uk> PS: I didn't even spend much time thinking how I would probably implement chkDup differently even for the generic case that you want to do. As in, intuition tells me you don't really need an applicative monoid internally to do what you're trying to do. But, as I said, haven't thought it thoroughly, and with the code I gave you, you get what you were trying to do and it's not "wrong". Maybe just overkill. Quoting Juan Casanova on Wed, 07 Aug 2019 12:17:27 +0100: > To build up on Paolino's answer, and maybe, if you're like me, give > you a better intuition as to why your code was incorrect, but > leading to essentially the same answer he gave. > > First, you didn't provide us with the type signatures for chkDup and > f, but I worked with the following ones to start with: > > chkDup :: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, > Foldable t, Foldable f, Applicative f, Monoid (f a)) => t a -> Bool > > f :: (Num a, Foldable t, Semigroup (t a), Applicative t, Eq a) => a > -> (Bool, t a) -> (Bool, t a) > > This gives me the same error you get even if I define chkDup _ = undefined. > > The problem is that you are providing class constraints for the type > f, which does not appear at all in the signature of the function (t > a -> Bool), and this makes the typechecker get super confused. Now, > I know why you thought this was necessary: precisely because of what > Paolino pointed out: mempty has an undefined type, and you tried to > fix this by saying "This mempty is of type f, which I don't care for > the type, just that it is a Semigroup and Applicative". But this is > a mistake. So, if you just remove the f altogether from the class > constraints of the chkDup type signature, and leave it like this: > > chkDup :: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, > Foldable t) => t a -> Bool > > You still get an error, but now you get the actual error message > that you're looking for: "Could not deduce Foldable t0 arising from > a use of f". > > The right way to fix this is how Paolino said: Specify what Foldable > you're going to use (recommended: list) (so, use [] instead of > mempty). The point is, since the type f is not part of the input NOR > the output of the function chkDup, and instead it is just an > internal tool that you use to compute chkDup, there's no reason to > want to be generic about it, there's no advantage in that. The > advantage in genericity using typeclasses is: 1. If it's in the > input, you allow the user of the function to provide you with any > type that fulfills the class. 2. You make it very clear that > everything you do with that parameter is related to its typeclass > instance, as there is no way to inspect the actual type. 3. If it's > in the output, you don't let users of the function make any > assumption of what that type might look like, other than its > typeclass instance. > > But in an internal tool that doesn't come from outside and isn't > output by your function, there's no reason to be generic, just use > lists. The only reason I could see being argued for wanting to be > generic would be if you'd like the user to provide you with hints as > to how to compute the function so that it's more efficient. If you > really want to go that far, I think there's other ways to do that, > that I haven't thought of right now. > > All in all, the following code works: > > chkDup :: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, > Foldable t) => t a -> Bool > chkDup ns = fst $ foldr f (False,[]) ns > > f :: (Num a, Foldable t, Semigroup (t a), Applicative t, Eq a) => a > -> (Bool, t a) -> (Bool, t a) > f _ res@(True,_) = res > f v res@(_,vs) = if v==0 then (False, vs) else (elem v vs, pure v <> vs) > > I hope you found that useful. > > Juan. > > Quoting Paolino on Wed, 7 Aug 2019 > 13:05:39 +0200: > >> So about the type error, the second element of the tuple has no defined >> type. You can fix it substituting (pure v) with [v] if you want a list >> there. >> >> Also >> >> - chkDup ns = any (`elem` ns) >> - use Set.member to reduce complexity >> >> Best >> >> On Wed, 7 Aug 2019 at 11:53, Dušan Kolář wrote: >> >>> Dear Café, >>> >>> >>> >>> I'm trying to solve a couple of examples and exercises just for me. I've >>> come to the point, when I'm trying working code manipulating lists rewrite >>> to work on Foldable (etc.). >>> >>> >>> >>> Nevertheless, I must be doing some mistake, overlooking something, as >>> simple code like this: >>> >>> >>> >>> chkDup [] = False >>> >>> chkDup (0:ns) = chkDup ns >>> >>> chkDup (n:ns) = elem n ns || chkDup ns >>> >>> >>> >>> which works fine, type-checks, can be used within other code, I'm trying >>> to replace with more generic, but probably less efficient and wrong code: >>> >>> >>> >>> chkDup ns = fst $ foldr f (False,mempty) ns >>> >>> where >>> >>> f _ res@(True,_) = res >>> >>> f v res@(_,vs) = if v==0 then (False, vs) else (elem v vs, pure v <> vs) >>> >>> >>> >>> which does not even type-check. >>> >>> >>> >>> Nevertheless, the error message is not too helpful, searching the Internet >>> just confirms it's wrong and that adding AllowAmbiguousTypes would not >>> work. The error message is: >>> >>> >>> >>> helper.hs:49:1: error: >>> >>> • Could not deduce (Foldable f0) >>> >>> from the context: (Eq a, Num a, Foldable t, Foldable f, >>> >>> Applicative f, Monoid (f a)) >>> >>> bound by the inferred type for ‘chkDup’: >>> >>> forall a (t :: * -> *) (f :: * -> *). >>> >>> (Eq a, Num a, Foldable t, Foldable f, Applicative f, >>> >>> Monoid (f a)) => >>> >>> t a -> Bool >>> >>> at helper.hs:(49,1)-(53,80) >>> >>> The type variable ‘f0’ is ambiguous >>> >>> • In the ambiguity check for the inferred type for ‘chkDup’ >>> >>> To defer the ambiguity check to use sites, enable AllowAmbiguousTypes >>> >>> When checking the inferred type >>> >>> chkDup :: forall a (t :: * -> *) (f :: * -> *). >>> >>> (Eq a, Num a, Foldable t, Foldable f, Applicative f, >>> >>> Monoid (f a)) => >>> >>> t a -> Bool >>> >>> | >>> >>> 49 | chkDup ns = >>> >>> | ^^^^^^^^^^^... >>> >>> >>> >>> >>> >>> So is there a nicer and working way, how to change my simple example? Is >>> there a way, how to make it compile? Or is it useless to do that, original >>> function is just fine... >>> >>> >>> >>> Best regards, >>> >>> Dušan >>> >>> >>> _______________________________________________ >>> Haskell-Cafe mailing list >>> To (un)subscribe, modify options or view archives go to: >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >>> Only members subscribed via the mailman list are allowed to post. >> >> >> >> -- >> >> Paolo Veronelli (paolo.veronelli at gmail.com) >> >> >> *Functional developer @ global.de * >> > > > > -- > The University of Edinburgh is a charitable body, registered in > Scotland, with registration number SC005336. > > > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -- The University of Edinburgh is a charitable body, registered in Scotland, with registration number SC005336. From paolo.veronelli at gmail.com Wed Aug 7 11:37:53 2019 From: paolo.veronelli at gmail.com (Paolino) Date: Wed, 7 Aug 2019 13:37:53 +0200 Subject: [Haskell-cafe] Ambiguous types In-Reply-To: References: <2162795.o9Qe6PU3hX@pckolar> Message-ID: I will try again to repair my rushing on the code side I'm interpreting that [0,0,1] -> False [0,1,2,1] -> True To remove the explicit recursion, and noticing the 0 case any (\(x:xs) -> x `elem` xs) . init . tails . filter (/= 0) -- quadratic but exit soon any identity . (zipWith (==) <*> tail) . sort . filter (/= 0) -- n log n , but has to sort always I'm not sure, what the other code should do with the accumulated part , as it accumulates duplicates too and forget about the previous boolean Hope I read it enough carefully now , to be helpful. Best On Wed, 7 Aug 2019 at 13:13, Paolino wrote: > Pardon, delete my code. I rushed the answer without reading carefully, my > bad. > > > On Wed, 7 Aug 2019 at 13:05, Paolino wrote: > >> So about the type error, the second element of the tuple has no defined >> type. You can fix it substituting (pure v) with [v] if you want a list >> there. >> >> Also >> >> - chkDup ns = any (`elem` ns) >> - use Set.member to reduce complexity >> >> Best >> >> On Wed, 7 Aug 2019 at 11:53, Dušan Kolář wrote: >> >>> Dear Café, >>> >>> >>> >>> I'm trying to solve a couple of examples and exercises just for me. I've >>> come to the point, when I'm trying working code manipulating lists rewrite >>> to work on Foldable (etc.). >>> >>> >>> >>> Nevertheless, I must be doing some mistake, overlooking something, as >>> simple code like this: >>> >>> >>> >>> chkDup [] = False >>> >>> chkDup (0:ns) = chkDup ns >>> >>> chkDup (n:ns) = elem n ns || chkDup ns >>> >>> >>> >>> which works fine, type-checks, can be used within other code, I'm trying >>> to replace with more generic, but probably less efficient and wrong code: >>> >>> >>> >>> chkDup ns = fst $ foldr f (False,mempty) ns >>> >>> where >>> >>> f _ res@(True,_) = res >>> >>> f v res@(_,vs) = if v==0 then (False, vs) else (elem v vs, pure v <> vs) >>> >>> >>> >>> which does not even type-check. >>> >>> >>> >>> Nevertheless, the error message is not too helpful, searching the >>> Internet just confirms it's wrong and that adding AllowAmbiguousTypes would >>> not work. The error message is: >>> >>> >>> >>> helper.hs:49:1: error: >>> >>> • Could not deduce (Foldable f0) >>> >>> from the context: (Eq a, Num a, Foldable t, Foldable f, >>> >>> Applicative f, Monoid (f a)) >>> >>> bound by the inferred type for ‘chkDup’: >>> >>> forall a (t :: * -> *) (f :: * -> *). >>> >>> (Eq a, Num a, Foldable t, Foldable f, Applicative f, >>> >>> Monoid (f a)) => >>> >>> t a -> Bool >>> >>> at helper.hs:(49,1)-(53,80) >>> >>> The type variable ‘f0’ is ambiguous >>> >>> • In the ambiguity check for the inferred type for ‘chkDup’ >>> >>> To defer the ambiguity check to use sites, enable AllowAmbiguousTypes >>> >>> When checking the inferred type >>> >>> chkDup :: forall a (t :: * -> *) (f :: * -> *). >>> >>> (Eq a, Num a, Foldable t, Foldable f, Applicative f, >>> >>> Monoid (f a)) => >>> >>> t a -> Bool >>> >>> | >>> >>> 49 | chkDup ns = >>> >>> | ^^^^^^^^^^^... >>> >>> >>> >>> >>> >>> So is there a nicer and working way, how to change my simple example? Is >>> there a way, how to make it compile? Or is it useless to do that, original >>> function is just fine... >>> >>> >>> >>> Best regards, >>> >>> Dušan >>> >>> >>> _______________________________________________ >>> Haskell-Cafe mailing list >>> To (un)subscribe, modify options or view archives go to: >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >>> Only members subscribed via the mailman list are allowed to post. >> >> >> >> -- >> >> Paolo Veronelli (paolo.veronelli at gmail.com) >> >> >> *Functional developer @ global.de * >> >> > > -- > > Paolo Veronelli (paolo.veronelli at gmail.com) > > > *Functional developer @ global.de * > > -- Paolo Veronelli (paolo.veronelli at gmail.com) *Functional developer @ global.de * -------------- next part -------------- An HTML attachment was scrubbed... URL: From kolar at fit.vut.cz Wed Aug 7 12:38:12 2019 From: kolar at fit.vut.cz (=?utf-8?B?RHXFoWFuIEtvbMOhxZk=?=) Date: Wed, 07 Aug 2019 14:38:12 +0200 Subject: [Haskell-cafe] Ambiguous types In-Reply-To: <20190807122127.14952dhisipgjr6s@www.staffmail.ed.ac.uk> References: <2162795.o9Qe6PU3hX@pckolar> <20190807121727.18661n6493o30sis@www.staffmail.ed.ac.uk> <20190807122127.14952dhisipgjr6s@www.staffmail.ed.ac.uk> Message-ID: <21769040.ac4hKd0Jlg@pckolar> Thanks all for the answers, and no, they are not what I was asking for... Not providing type signatures, yes, no type signatures provided, GHC should derive them on its own. My question was, why it is not able to do that and how force GHC to do that. Without extra type info... The original type signature was simple: chkDup :: (Eq a, Num a) => [a] -> Bool I would be quite happy to have something similar, just for [] to have some generic type - auto-magically :-) And no, my intention was not to make it a bit faster for larger inputs, just make clear and clean code without extra type signatures, easy to read and simple to understand. Real-life input has 36 six members at most. And no, I don't want the general code to be specific for lists, thus no extra type signatures or changes to make it more list of Ints. So thank you once again, unfortunately, my conclusion is that writing generic code is not always beneficial - neither for reading nor for generality... Thank you once again, Dušan On středa 7. srpna 2019 13:21:27 CEST Juan Casanova wrote: > PS: I didn't even spend much time thinking how I would probably > implement chkDup differently even for the generic case that you want > to do. As in, intuition tells me you don't really need an applicative > monoid internally to do what you're trying to do. But, as I said, > haven't thought it thoroughly, and with the code I gave you, you get > what you were trying to do and it's not "wrong". Maybe just overkill. > > Quoting Juan Casanova on Wed, 07 Aug 2019 > > 12:17:27 +0100: > > To build up on Paolino's answer, and maybe, if you're like me, give > > you a better intuition as to why your code was incorrect, but > > leading to essentially the same answer he gave. > > > > First, you didn't provide us with the type signatures for chkDup and > > f, but I worked with the following ones to start with: > > > > chkDup :: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, > > Foldable t, Foldable f, Applicative f, Monoid (f a)) => t a -> Bool > > > > f :: (Num a, Foldable t, Semigroup (t a), Applicative t, Eq a) => a > > -> (Bool, t a) -> (Bool, t a) > > > > This gives me the same error you get even if I define chkDup _ = > > undefined. > > > > The problem is that you are providing class constraints for the type > > f, which does not appear at all in the signature of the function (t > > a -> Bool), and this makes the typechecker get super confused. Now, > > I know why you thought this was necessary: precisely because of what > > Paolino pointed out: mempty has an undefined type, and you tried to > > fix this by saying "This mempty is of type f, which I don't care for > > the type, just that it is a Semigroup and Applicative". But this is > > a mistake. So, if you just remove the f altogether from the class > > constraints of the chkDup type signature, and leave it like this: > > > > chkDup :: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, > > Foldable t) => t a -> Bool > > > > You still get an error, but now you get the actual error message > > that you're looking for: "Could not deduce Foldable t0 arising from > > a use of f". > > > > The right way to fix this is how Paolino said: Specify what Foldable > > you're going to use (recommended: list) (so, use [] instead of > > mempty). The point is, since the type f is not part of the input NOR > > the output of the function chkDup, and instead it is just an > > internal tool that you use to compute chkDup, there's no reason to > > want to be generic about it, there's no advantage in that. The > > advantage in genericity using typeclasses is: 1. If it's in the > > input, you allow the user of the function to provide you with any > > type that fulfills the class. 2. You make it very clear that > > everything you do with that parameter is related to its typeclass > > instance, as there is no way to inspect the actual type. 3. If it's > > in the output, you don't let users of the function make any > > assumption of what that type might look like, other than its > > typeclass instance. > > > > But in an internal tool that doesn't come from outside and isn't > > output by your function, there's no reason to be generic, just use > > lists. The only reason I could see being argued for wanting to be > > generic would be if you'd like the user to provide you with hints as -------------- next part -------------- An HTML attachment was scrubbed... URL: From juan.casanova at ed.ac.uk Wed Aug 7 12:53:17 2019 From: juan.casanova at ed.ac.uk (Juan Casanova) Date: Wed, 07 Aug 2019 13:53:17 +0100 Subject: [Haskell-cafe] Ambiguous types In-Reply-To: <21769040.ac4hKd0Jlg@pckolar> References: <2162795.o9Qe6PU3hX@pckolar> <20190807121727.18661n6493o30sis@www.staffmail.ed.ac.uk> <20190807122127.14952dhisipgjr6s@www.staffmail.ed.ac.uk> <21769040.ac4hKd0Jlg@pckolar> Message-ID: <20190807135317.785373zpisqog4g0@www.staffmail.ed.ac.uk> There are two important things to say about your e-mail, but one is a lot more important than the other. > And no, I don't want the general code to be specific for lists, thus > no extra type > signatures or changes to make it more list of Ints. You did not understand my (and Paolino's) point about using lists. By using lists *internally* you're not making it less generic. The function still works for any foldable. But you are building another foldable *within your function* as a way to check for duplication, that isn't returned. When you build an element, you need to specify it's type (or use a function passed as parameter to build it). In this case, list is just as good as any other foldable for the internal workings. You can use another foldable if you wish, but you need to use some foldable, because Foldable itself is only a behavioural definition that cannot be used directly. Thus, what I personally said about efficiency was in the case that you wanted the user to be able to *specify as an argument* what instance of Foldable to use for this. If you don't care about efficiency, then use lists, or any other foldable of your choice. Let me see if I can make this clearer with an analogy. You go to a workshop and ask them to build a metal bar for you. You say: it needs to be this size, this weight and be able to resist this amount of strength (that would be equivalent to the typeclass, it needs to be Foldable). Now, what would break the transparency that typeclasses and genericity provide would be if they asked you: "what are you going to use this metal bar for?". They don't need to know, as long as they produce a metal bar that fulfills your requirements. So far so good. But now, imagine that you asked them: "I want you to build the metal bar in such a way that it is independent of the tools that you have available". They would be puzzled. Why do you care what tools they use to build the metal bar? You want a metal bar with a set of characteristics, you will get it. How they build the metal bar and how specific that building of the metal bar may be is absolutely irrelevant to you. This is the list. The list (or any other foldable that you wish to use), is just the tool that you use to check for duplicity. It is *not* the output result of your function. So using it does not break genericity in any way. The second, slightly less important point, is about the type signatures. You want GHC to derive the signatures on its own? Fine. Take the code that I provided you, and remove the type signatures. It compiles, it works, and it infers exactly the same type signatures that I provided. There are two reasons for which I think your approach that "it is better if I don't specify the type signatures" is mistaken. First, the reason you want to provide type signatures is because it makes the code clearer. Saying that "GHC should derive the type signatures" is a bit like writing a mono-function program and saying "the compiler should not care about how long my functions are". Type signatures help the programmer understand what the functions do, help you program by making it easier to see if you can use a function or not by looking at its type signature, and make it easier to debug by modularizing the problems. Second, depending on what extensions you use (and you are using RankNTypes and KindSignatures, which are not trivial extensions), type signatures on functions or type annotations might not be avoidable, precisely because of ambiguity. In this particular case, they can be removed, as I said, but there are some programs that are inevitably ambiguous unless you explicitly specify the types. And this is not a GHC limitation, it is a mathematical limitation of the programming model, so type signatures are not optional sometimes. But, as I said, if you really disagree and prefer not to provide type signatures, then don't. The code I provided still works perfectly, and the reason why using lists internally does not break genericity still holds regardless of that. Juan. Quoting Dušan Kolář on Wed, 07 Aug 2019 14:38:12 +0200: > Thanks all for the answers, and no, they are not what I was asking for... > > Not providing type signatures, yes, no type signatures provided, GHC > should derive > them on its own. My question was, why it is not able to do that and > how force GHC > to do that. Without extra type info... > > The original type signature was simple: chkDup :: (Eq a, Num a) => > [a] -> Bool > I would be quite happy to have something similar, just for [] to > have some generic > type - auto-magically :-) > > And no, my intention was not to make it a bit faster for larger > inputs, just make > clear and clean code without extra type signatures, easy to read and > simple to > understand. Real-life input has 36 six members at most. > > > So thank you once again, unfortunately, my conclusion is that > writing generic code > is not always beneficial - neither for reading nor for generality... > > Thank you once again, > > Dušan > > -- The University of Edinburgh is a charitable body, registered in Scotland, with registration number SC005336. From jaro.reinders at gmail.com Wed Aug 7 12:59:43 2019 From: jaro.reinders at gmail.com (Jaro Reinders) Date: Wed, 7 Aug 2019 14:59:43 +0200 Subject: [Haskell-cafe] Ambiguous types In-Reply-To: <21769040.ac4hKd0Jlg@pckolar> References: <2162795.o9Qe6PU3hX@pckolar> <20190807121727.18661n6493o30sis@www.staffmail.ed.ac.uk> <20190807122127.14952dhisipgjr6s@www.staffmail.ed.ac.uk> <21769040.ac4hKd0Jlg@pckolar> Message-ID: <2e43bcf1-46cc-b830-c565-cce65ba8a522@gmail.com> Another issue with not providing a type signature on internal types is that the code can literally change meaning. In this case we can change the meaning of your code by simply adding a type signature: chkDup ns = fst $ foldr f (False,mempty :: (Semigroup a, Num a, Eq a) => Maybe a) ns where f _ res@(True,_) = res f v res@(_,vs) = if v==0 then (False, vs) else (elem v vs, pure v <> vs) Now the code doesn't do what you want anymore. How should GHC be able to infer the types if an expression can have two different types that have different meanings? On 07-08-2019 14:38, Dušan Kolář wrote: > Thanks all for the answers, and no, they are not what I was asking for... > > Not providing type signatures, yes, no type signatures provided, GHC should derive > them on its own. My question was, why it is not able to do that and how force GHC > to do that. Without extra type info... > > The original type signature was simple: chkDup :: (Eq a, Num a) => [a] -> Bool > I would be quite happy to have something similar, just for [] to have some generic > type - auto-magically :-) > > And no, my intention was not to make it a bit faster for larger inputs, just make > clear and clean code without extra type signatures, easy to read and simple to > understand. Real-life input has 36 six members at most. > > And no, I don't want the general code to be specific for lists, thus no extra type > signatures or changes to make it more list of Ints. > > So thank you once again, unfortunately, my conclusion is that writing generic code > is not always beneficial - neither for reading nor for generality... > > Thank you once again, > > Dušan > > > On středa 7. srpna 2019 13:21:27 CEST Juan Casanova wrote: >> PS: I didn't even spend much time thinking how I would probably >> implement chkDup differently even for the generic case that you want >> to do. As in, intuition tells me you don't really need an applicative >> monoid internally to do what you're trying to do. But, as I said, >> haven't thought it thoroughly, and with the code I gave you, you get >> what you were trying to do and it's not "wrong". Maybe just overkill. >> >> Quoting Juan Casanova on Wed, 07 Aug 2019 >> >> 12:17:27 +0100: >>> To build up on Paolino's answer, and maybe, if you're like me, give >>> you a better intuition as to why your code was incorrect, but >>> leading to essentially the same answer he gave. >>> >>> First, you didn't provide us with the type signatures for chkDup and >>> f, but I worked with the following ones to start with: >>> >>> chkDup :: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, >>> Foldable t, Foldable f, Applicative f, Monoid (f a)) => t a -> Bool >>> >>> f :: (Num a, Foldable t, Semigroup (t a), Applicative t, Eq a) => a >>> -> (Bool, t a) -> (Bool, t a) >>> >>> This gives me the same error you get even if I define chkDup _ = >>> undefined. >>> >>> The problem is that you are providing class constraints for the type >>> f, which does not appear at all in the signature of the function (t >>> a -> Bool), and this makes the typechecker get super confused. Now, >>> I know why you thought this was necessary: precisely because of what >>> Paolino pointed out: mempty has an undefined type, and you tried to >>> fix this by saying "This mempty is of type f, which I don't care for >>> the type, just that it is a Semigroup and Applicative". But this is >>> a mistake. So, if you just remove the f altogether from the class >>> constraints of the chkDup type signature, and leave it like this: >>> >>> chkDup :: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, >>> Foldable t) => t a -> Bool >>> >>> You still get an error, but now you get the actual error message >>> that you're looking for: "Could not deduce Foldable t0 arising from >>> a use of f". >>> >>> The right way to fix this is how Paolino said: Specify what Foldable >>> you're going to use (recommended: list) (so, use [] instead of >>> mempty). The point is, since the type f is not part of the input NOR >>> the output of the function chkDup, and instead it is just an >>> internal tool that you use to compute chkDup, there's no reason to >>> want to be generic about it, there's no advantage in that. The >>> advantage in genericity using typeclasses is: 1. If it's in the >>> input, you allow the user of the function to provide you with any >>> type that fulfills the class. 2. You make it very clear that >>> everything you do with that parameter is related to its typeclass >>> instance, as there is no way to inspect the actual type. 3. If it's >>> in the output, you don't let users of the function make any >>> assumption of what that type might look like, other than its >>> typeclass instance. >>> >>> But in an internal tool that doesn't come from outside and isn't >>> output by your function, there's no reason to be generic, just use >>> lists. The only reason I could see being argued for wanting to be >>> generic would be if you'd like the user to provide you with hints as >>> >>> _______________________________________________ >>> Haskell-Cafe mailing list >>> To (un)subscribe, modify options or view archives go to: >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >>> Only members subscribed via the mailman list are allowed to post. From juan.casanova at ed.ac.uk Wed Aug 7 13:22:25 2019 From: juan.casanova at ed.ac.uk (Juan Casanova) Date: Wed, 07 Aug 2019 14:22:25 +0100 Subject: [Haskell-cafe] Ambiguous types In-Reply-To: <2e43bcf1-46cc-b830-c565-cce65ba8a522@gmail.com> References: <2162795.o9Qe6PU3hX@pckolar> <20190807121727.18661n6493o30sis@www.staffmail.ed.ac.uk> <20190807122127.14952dhisipgjr6s@www.staffmail.ed.ac.uk> <21769040.ac4hKd0Jlg@pckolar> <2e43bcf1-46cc-b830-c565-cce65ba8a522@gmail.com> Message-ID: <20190807142225.11373snkepghqc2s@www.staffmail.ed.ac.uk> To add and tie this in with the list choice, I must say I said something not entirely correct: Not any foldable that you may want to use is valid. As Jaro showed here, Maybe is a Foldable that would not do what you want. Now, I have no proof of the following, but I'd bet money that I'm not wrong that: List is special as a foldable because it is general. In other words, the function: tolist :: Foldable t => t a -> [a] tolist = foldr (:) [] is such that for any x :: t a where Foldable t, it is true that foldr f v x = foldr f v (tolist x) which is to say, any structure a foldable may have is preserved when transforming into list shape, as a foldable. This is not an argument for saying "let's use lists all the time instead of foldables". Of course not. But, *internally*, you can use lists so that the program can run (because it needs an instance), while knowing that you will not be losing any structure while using lists, so that the overall function will work for any foldable. I think I'll stop my ramblings now, I don't want to overload the list. Quoting Jaro Reinders on Wed, 7 Aug 2019 14:59:43 +0200: > Another issue with not providing a type signature on internal types is > that the code can literally change meaning. In this case we can change > the meaning of your code by simply adding a type signature: > > chkDup ns = fst $ foldr f (False,mempty :: (Semigroup a, Num a, Eq a) => > Maybe a) ns > where > f _ res@(True,_) = res > f v res@(_,vs) = if v==0 then (False, vs) else (elem v vs, pure v <> vs) > > Now the code doesn't do what you want anymore. How should GHC be able to > infer the types if an expression can have two different types that have > different meanings? > > On 07-08-2019 14:38, Dušan Kolář wrote: >> Thanks all for the answers, and no, they are not what I was asking for... >> >> Not providing type signatures, yes, no type signatures provided, >> GHC should derive >> them on its own. My question was, why it is not able to do that and >> how force GHC >> to do that. Without extra type info... >> >> The original type signature was simple: chkDup :: (Eq a, Num a) => >> [a] -> Bool >> I would be quite happy to have something similar, just for [] to >> have some generic >> type - auto-magically :-) >> >> And no, my intention was not to make it a bit faster for larger >> inputs, just make >> clear and clean code without extra type signatures, easy to read >> and simple to >> understand. Real-life input has 36 six members at most. >> >> And no, I don't want the general code to be specific for lists, >> thus no extra type >> signatures or changes to make it more list of Ints. >> >> So thank you once again, unfortunately, my conclusion is that >> writing generic code >> is not always beneficial - neither for reading nor for generality... >> >> Thank you once again, >> >> Dušan >> >> >> On středa 7. srpna 2019 13:21:27 CEST Juan Casanova wrote: >>> PS: I didn't even spend much time thinking how I would probably >>> implement chkDup differently even for the generic case that you want >>> to do. As in, intuition tells me you don't really need an applicative >>> monoid internally to do what you're trying to do. But, as I said, >>> haven't thought it thoroughly, and with the code I gave you, you get >>> what you were trying to do and it's not "wrong". Maybe just overkill. >>> >>> Quoting Juan Casanova on Wed, 07 Aug 2019 >>> >>> 12:17:27 +0100: >>>> To build up on Paolino's answer, and maybe, if you're like me, give >>>> you a better intuition as to why your code was incorrect, but >>>> leading to essentially the same answer he gave. >>>> >>>> First, you didn't provide us with the type signatures for chkDup and >>>> f, but I worked with the following ones to start with: >>>> >>>> chkDup :: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, >>>> Foldable t, Foldable f, Applicative f, Monoid (f a)) => t a -> Bool >>>> >>>> f :: (Num a, Foldable t, Semigroup (t a), Applicative t, Eq a) => a >>>> -> (Bool, t a) -> (Bool, t a) >>>> >>>> This gives me the same error you get even if I define chkDup _ = >>>> undefined. >>>> >>>> The problem is that you are providing class constraints for the type >>>> f, which does not appear at all in the signature of the function (t >>>> a -> Bool), and this makes the typechecker get super confused. Now, >>>> I know why you thought this was necessary: precisely because of what >>>> Paolino pointed out: mempty has an undefined type, and you tried to >>>> fix this by saying "This mempty is of type f, which I don't care for >>>> the type, just that it is a Semigroup and Applicative". But this is >>>> a mistake. So, if you just remove the f altogether from the class >>>> constraints of the chkDup type signature, and leave it like this: >>>> >>>> chkDup :: forall a (t :: * -> *) (f :: * -> *). (Eq a, Num a, >>>> Foldable t) => t a -> Bool >>>> >>>> You still get an error, but now you get the actual error message >>>> that you're looking for: "Could not deduce Foldable t0 arising from >>>> a use of f". >>>> >>>> The right way to fix this is how Paolino said: Specify what Foldable >>>> you're going to use (recommended: list) (so, use [] instead of >>>> mempty). The point is, since the type f is not part of the input NOR >>>> the output of the function chkDup, and instead it is just an >>>> internal tool that you use to compute chkDup, there's no reason to >>>> want to be generic about it, there's no advantage in that. The >>>> advantage in genericity using typeclasses is: 1. If it's in the >>>> input, you allow the user of the function to provide you with any >>>> type that fulfills the class. 2. You make it very clear that >>>> everything you do with that parameter is related to its typeclass >>>> instance, as there is no way to inspect the actual type. 3. If it's >>>> in the output, you don't let users of the function make any >>>> assumption of what that type might look like, other than its >>>> typeclass instance. >>>> >>>> But in an internal tool that doesn't come from outside and isn't >>>> output by your function, there's no reason to be generic, just use >>>> lists. The only reason I could see being argued for wanting to be >>>> generic would be if you'd like the user to provide you with hints as >>>> >>>> _______________________________________________ >>>> Haskell-Cafe mailing list >>>> To (un)subscribe, modify options or view archives go to: >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >>>> Only members subscribed via the mailman list are allowed to post. > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -- The University of Edinburgh is a charitable body, registered in Scotland, with registration number SC005336. From byorgey at gmail.com Wed Aug 7 13:36:42 2019 From: byorgey at gmail.com (Brent Yorgey) Date: Wed, 7 Aug 2019 08:36:42 -0500 Subject: [Haskell-cafe] Ambiguous types In-Reply-To: <20190807142225.11373snkepghqc2s@www.staffmail.ed.ac.uk> References: <2162795.o9Qe6PU3hX@pckolar> <20190807121727.18661n6493o30sis@www.staffmail.ed.ac.uk> <20190807122127.14952dhisipgjr6s@www.staffmail.ed.ac.uk> <21769040.ac4hKd0Jlg@pckolar> <2e43bcf1-46cc-b830-c565-cce65ba8a522@gmail.com> <20190807142225.11373snkepghqc2s@www.staffmail.ed.ac.uk> Message-ID: On Wed, Aug 7, 2019, 8:22 AM Juan Casanova wrote: > List is special as a foldable because it is general. In > other words, the function: > > tolist :: Foldable t => t a -> [a] > tolist = foldr (:) [] > > is such that for any x :: t a where Foldable t, it is true that > > foldr f v x = foldr f v (tolist x) > > which is to say, any structure a foldable may have is preserved when > transforming into list shape, as a foldable. > This is true. In fact "Listable" might have been a better name than Foldable. (In particular Foldable has nothing to do with generic folds aka catamorphisms.) -Brent > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ietf-dane at dukhovni.org Wed Aug 7 22:49:54 2019 From: ietf-dane at dukhovni.org (Viktor Dukhovni) Date: Wed, 7 Aug 2019 18:49:54 -0400 Subject: [Haskell-cafe] Ambiguous types In-Reply-To: <2162795.o9Qe6PU3hX@pckolar> References: <2162795.o9Qe6PU3hX@pckolar> Message-ID: <41D9E14F-EA62-4848-BD13-0A7D703F8B79@dukhovni.org> > On Aug 7, 2019, at 5:52 AM, Dušan Kolář wrote: > > So is there a nicer and working way, how to change my simple example? Is there a way, how to make it compile? Or is it useless to do that, original function is just fine... The closest working version is: checkDup ns = fst $ foldr f (False, []) ns where f _ res@(True, _) = res f 0 res@(_, vs) = (False, vs) f v res@(_, vs) = (elem v vs, v : vs) replacing "mempty" with "[]" removes the ambiguity, which is was a logical inevitability, and not some limitation of GHC's type inference... -- Viktor. From adam at ahri.net Fri Aug 9 15:28:08 2019 From: adam at ahri.net (Adam) Date: Fri, 9 Aug 2019 16:28:08 +0100 Subject: [Haskell-cafe] Unifying an IO read into a TChan? Message-ID: Hello Café! It's my first post here so do tell me if I get something wrong :) I'm in the process of writing an event database; it should adhere to ACID principles and is specifically aimed at persisting then broadcasting events in some event-driven system. The code is up on GitHub and I expect to build a Hackage package soon, for now I'm prototyping with Stack generating the .cabal file, but this will change when things settle down. My question is about a function I have: readEvents :: Word64 -> Connection -> IO ([IndexedEvent], TChan IndexedEvent) readEvents from conn = do (ec, chan) <- atomically $ (,) <$> (readTVar $ evCount conn) <*> (dupTChan $ readSubs conn) evsFromDisk <- readEventsRange from ec conn pure (evsFromDisk, chan) For context please see the whole file: https://github.com/ahri/eventdb/blob/4747afb/src/Database/EventDB.hs#L172-L180 1. What I'd like to understand is how I might unify the return type into a single `TChan IndexedEvent` which would contain first the `evsFromDisk` and then pull from the broadcast channel `chan`. The only way I can think to do it is to fork a thread to write to a new broadcast channel - which might be unexpected for a client of my API and seems quite heavyweight. I have a connected couple of questions too, related to lazy IO as I'm still learning Haskell! 2. does my `readEventsRange` function pull all events into memory or does lazy IO magically avoid this by streaming the data through from the disk? 3. if I did fork a thread and write the `evsFromDisk` and the sit in a ` forever` reading off `chan` and onto my new broadcast channel, would this result in all the written events being read into memory or does the laziness spread so that only when the client does a `readTChan` will the data flow through from the disk/`chan`? Thanks for reading, Adam -------------- next part -------------- An HTML attachment was scrubbed... URL: From komendantskaya at gmail.com Mon Aug 12 07:29:07 2019 From: komendantskaya at gmail.com (Ekaterina Komendantskaya) Date: Mon, 12 Aug 2019 08:29:07 +0100 Subject: [Haskell-cafe] PADL 2020 (co-allocated with POPL 2020): first call for papers Message-ID: 22nd International Symposium on Practical Aspects of Declarative Languages (PADL 2020)https://popl20.sigplan.org/home/PADL-2020,20-21 January 2019, New Orleans, Louisiana, United StatesCo-located with ACM POPL 2020 ( https://popl20.sigplan.org/) ------------------------------ *Declarative programming languages* is an umbrella term for functional, logic, answer-set and constraint-solving programming paradigms, as well as a range of verification and theorem proving methods that rely on such languages. These languages have been successfully applied to many different real-world situations, ranging from data base management and active networks to software engineering and decision support systems. New developments in theory and implementation have opened up new application areas. At the same time, applications of declarative languages to challenging problems raise new intriguing research questions, such as scalable design and implementation, language extensions for application deployment, and programming environments. Thus, applications drive the progress in the theory and implementation of declarative systems, and benefit from this progress as well. PADL is a well-established forum for researchers and practitioners to present original work emphasising novel applications and implementation techniques for all forms of declarative programming, including functional and logic programming, data-base and constraint programming, theorem proving. Topics of interest include, but are not limited to: - Innovative applications of declarative languages - Declarative domain-specific languages and applications - Practical applications of theoretical results - New language developments and their impact on applications - Declarative languages for software engineering - Evaluation of implementation techniques on practical applications - Practical experiences and industrial applications - Novel uses of declarative languages in the classroom - Practical languages and extensions such as probabilistic and reactive languages *PADL 2020 especially welcomes new ideas and approaches pertaining to applications, design and implementation of declarative languages going beyond the scope of the past PADL symposia, for example database languages and contract languages.* Important Dates and Submission Guidelines: - Abstracts due: 11 October 2019 - Papers due: 18 October 2019 - Notification to authors: 18 November 2019 - Camera-ready: 29 November 2020 Authors should submit an electronic copy of the full paper in PDF using the Springer LNCS format. The submission will be done through EasyChair conference system: https://easychair.org/conferences/?conf=padl2020 All submissions must be original work written in English. Submissions must be unpublished and not submitted for publication elsewhere. Work that already appeared in unpublished or informally published workshops proceedings may be submitted but the authors should notify the program chair about the place on which it has previously appeared. PADL 2020 will accept both technical and application papers: *Technical papers* must describe original, previously unpublished research results. Technical papers must not exceed 15 pages (plus one page of references) in Springer LNCS format. *Application papers* are a mechanism to present important practical applications of declarative languages that occur in industry or in areas of research other than Computer Science. Application papers are expected to describe complex and/or real-world applications that rely on an innovative use of declarative languages. Application descriptions, engineering solutions and real-world experiences (both positive and negative) are solicited. The limit for application papers is 8 pages in Springer LNCS format but such papers can also point to sites with supplemental information about the application or the system that they describe. *The proceedings of PADL 2020 will appear in the LNCS series of Springer Verlag: https://www.springer.com/gp/computer-science/lncs .* ************************************************************* For further questions, please contact the conference chairs: Ekaterina Komendantskaya and Annie Liu -------------- next part -------------- An HTML attachment was scrubbed... URL: From S.J.Thompson at kent.ac.uk Mon Aug 12 12:33:55 2019 From: S.J.Thompson at kent.ac.uk (Simon Thompson) Date: Mon, 12 Aug 2019 13:33:55 +0100 Subject: [Haskell-cafe] Research Associate at Kent in Trustworthy Refactoring Message-ID: <5B9C56E6-34C2-4553-845C-141275DAB55A@kent.ac.uk> We are seeking to recruit an enthusiastic Research Associate to join the final year of the EPSRC project “Trustworthy Refactoring”. The overall goal of this project is to investigate the design and construction of trustworthy refactoring tools: this means that when refactorings are performed, the tools will provide strong evidence that the refactoring has not changed the behaviour of the code, built on a solid theoretical understanding of the semantics of the language, thus establishing a step change in the practice of refactoring. If you have have a PhD in Computer Science, awarded or nearing completion, experience in functional programming (e.g. Haskell/ML/Erlang/…) and experience of using a proof assistant (e.g. Coq/Isabelle/HOL/…), you have what we’re looking for. More details about the project are here: https://jobs.kent.ac.uk/vacancy.aspx?ref=STM-047-19 If you have any questions about the post do contact one of us by email: Scott Owens (s.a.owens at kent.ac.uk) and Simon Thompson (s.j.thompson at kent.ac.uk) : we look forward to hearing from you. Scott and Simon Simon Thompson | Professor of Logic and Computation School of Computing | University of Kent | Canterbury, CT2 7NF, UK s.j.thompson at kent.ac.uk | M +44 7986 085754 | W www.cs.kent.ac.uk/~sjt From P.Achten at cs.ru.nl Thu Aug 15 11:23:26 2019 From: P.Achten at cs.ru.nl (Peter Achten) Date: Thu, 15 Aug 2019 13:23:26 +0200 Subject: [Haskell-cafe] [TFP'20] first call for papers: Trends in Functional Programming 2020, 13-14 February, Krakow, Poland Message-ID: -------------------------------------------------------------------------                      First call for papers         21st Symposium on Trends in Functional Programming                           tfp2020.org ------------------------------------------------------------------------- The symposium on Trends in Functional Programming (TFP) is an international forum for researchers with interests in all aspects of functional programming, taking a broad view of current and future trends in the area. It aspires to be a lively environment for presenting the latest research results, and other contributions. * TFP is moving to new winter dates, to provide an FP forum in between the   annual ICFP events. * TFP offers a supportive reviewing process designed to help less experienced   authors succeed, with two rounds of review, both before and after the   symposium itself. Authors have an opportunity to address reviewers' concerns   before final decisions on publication in the proceedings. * TFP offers two "best paper" awards, the John McCarthy award for best paper,   and the David Turner award for best student paper. * This year we are particularly excited to co-locate with Lambda Days in   beautiful Krakow. Lambda Days is a vibrant developer conference with hundreds   of attendees and a lively programme of talks on functional programming in   practice. TFP will be held in the same venue, and participants will be able   to session-hop between the two events. Important Dates --------------- Submission deadline for pre-symposium review:   15th November, 2019 Submission deadline for draft papers:           10th January, 2020 Symposium dates:                                13-14th February, 2020 Visit tfp2020.org for more information. From n.wu at imperial.ac.uk Fri Aug 16 08:27:42 2019 From: n.wu at imperial.ac.uk (Wu, Nicolas G) Date: Fri, 16 Aug 2019 08:27:42 +0000 Subject: [Haskell-cafe] PhD position at Imperial College London Message-ID: # PhD Position in Functional Programming: Effect Handlers at Imperial College London Applications are invited for a PhD student in Functional Programming under the supervision of Dr Nicolas Wu at Imperial College London. The project aims to enhance the applications of effects and handlers by developing scoped contextual operations and effects. There are two main interrelated topics: 1. Developing the foundations of operations and effects that are confined within a scope and that are sensitive to context, thus widening the applications of effect handlers. 2. Producing efficient implementations and demonstrating applications that allow programmers to combine and use such effects. Addressing these topics will deliver both theoretical insight to the academic community and practical benefits to software engineers. To apply for this position, you will need to have a strong background in at least one of the following areas: functional programming, programming language design, compilers, algebraic effects. A working understanding of Haskell is essential. Applicants are expected to have a First Class or Distinction Masters level degree, or equivalent, in a relevant scientific or technical discipline, such as computer science or mathematics. Applicants must be fluent in spoken and written English. The position is fully funded, covering tuition fees, travel funds and a stipend/bursary. The position is available to home, EU and overseas students. Studentship: Untaxed bursary of £17,009 per annum (2018/19 figure including London weighting plus home/EU fees) For more details on how to apply, please see the advertisement here: http://www.imperial.ac.uk/computing/prospective-students/courses/phd/scholarships/# listed under "PhD Position in Functional Programming: Effect Handlers". Early applications are strongly encouraged. Please be in touch with informal inquiries about the position with Dr Nicolas Wu (n.wu at imperial.ac.uk). From rudy at matela.com.br Sun Aug 18 15:36:52 2019 From: rudy at matela.com.br (Rudy Matela) Date: Sun, 18 Aug 2019 12:36:52 -0300 Subject: [Haskell-cafe] [ANN] express-0.1.2: manipulate dynamically typed Haskell expressions Message-ID: <20190818153652.j5arsaupf77a4fup@zero.localdomain> Hello Haskell-Café, I am happy to announce the [Express] library for Haskell. https://github.com/rudymatela/express Express allows manipulation of dynamically typed Haskell expressions. It is similar to Data.Dynamic but with support for encoding applications and variables. It provides an Expr type and over a hundred functions for building, evaluating, comparing, folding, canonicalizing and matching Exprs. [Express' Haddock documentation] is pretty comprehensive. The project [README] has a few examples showing how to use Express to: * create heterogeneous lists; * list valid applications between expressions; * generalize counterexamples; * automatically generate test properties. This library has its origins as an internal module of [Speculate] and [Extrapolate], I am now releasing it separetely hoping that it could be used for other purposes. To install it, just: $ cabal update $ cabal install express Then you're ready to use it: $ ghci > import Data.Express > let true = val True > :t true true :: Expr > print true True :: Bool > eval False true True -- Rudy [Express]: https://github.com/rudymatela/express [Express' Haddock documentation]: https://hackage.haskell.org/package/express/docs/Data-Express.html [README]: https://github.com/rudymatela/express#readme [Speculate]: https://github.com/rudymatela/speculate [Extrapolate]: https://github.com/rudymatela/extrapolate -------------- next part -------------- An HTML attachment was scrubbed... URL: From Graham.Hutton at nottingham.ac.uk Mon Aug 19 09:52:56 2019 From: Graham.Hutton at nottingham.ac.uk (Graham Hutton) Date: Mon, 19 Aug 2019 09:52:56 +0000 Subject: [Haskell-cafe] MPC 2019 - Call for Participation Message-ID: <4120D52D-42BA-470B-8FD1-C903E91E42D1@exmail.nottingham.ac.uk> Dear all, Registration is now open for the Mathematics of Program Construction (MPC) conference in Portugal. MPC 2019 will feature 15 research papers and 4 keynotes, and is co-located with Formal Methods 2019 and many other events. See you in Porto! https://tinyurl.com/MPC-Porto Best wishes, Graham Hutton Program Chair, MPC 2019 ====================================================================== *** CALL FOR PARTICIPATION -- MPC 2019 *** 13th International Conference on Mathematics of Program Construction 7-9 October 2019, Porto, Portugal Co-located with Formal Methods 2019 https://tinyurl.com/MPC-Porto ====================================================================== PROGRAM: https://tinyurl.com/yxvvc5vb ACCEPTED PAPERS: https://tinyurl.com/yyuhy8ze REGISTRATION AND TRAVEL: https://tinyurl.com/y4uetlsr KEYNOTE SPEAKERS: Assia Mahboubi (MPC) INRIA, France Annabelle McIver (MPC) Macquarie University, Australia Tony Hoare (UTP) Oxford University, UK Shriram Krishnamurthi (FM) Brown University, USA BACKGROUND: The International Conference on Mathematics of Program Construction (MPC) aims to promote the development of mathematical principles and techniques that are demonstrably practical and effective in the process of constructing computer programs. MPC 2019 will be held in Porto, Portugal from 7-9 October 2019, and is co-located with the International Symposium on Formal Methods, FM 2019. Previous conferences were held in Königswinter, Germany (2015); Madrid, Spain (2012); Québec City, Canada (2010); Marseille, France (2008); Kuressaare, Estonia (2006); Stirling, UK (2004); Dagstuhl, Germany (2002); Ponte de Lima, Portugal (2000); Marstrand, Sweden (1998); Kloster Irsee, Germany (1995); Oxford, UK (1992); Twente, The Netherlands (1989). PROGRAM COMMITTEE: Patrick Bahr IT University of Copenhagen, Denmark Richard Bird University of Oxford, UK Corina Cîrstea University of Southampton, UK Brijesh Dongol University of Surrey, UK João F. Ferreira University of Lisbon, Portugal Jennifer Hackett University of Nottingham, UK William Harrison University of Missouri, USA Ralf Hinze University of Kaiserslautern, Germany Zhenjiang Hu National Institute of Informatics, Japan Graham Hutton (chair) University of Nottingham, UK Cezar Ionescu University of Oxford, UK Mauro Jaskelioff National University of Rosario, Argentina Ranjit Jhala University of California, USA Gabriele Keller Utrecht University, The Netherlands Ekaterina Komendantskaya Heriot-Watt University, UK Chris Martens North Carolina State University, USA Bernhard Möller University of Augsburg, Germany Shin-Cheng Mu Academia Sinica, Taiwan Mary Sheeran Chalmers University of Technology, Sweden Alexandra Silva University College London, UK Georg Struth University of Sheffield, UK For any queries about the program please contact the program chair, Graham Hutton . CONFERENCE VENUE: The conference will be held at the Alfândega Porto Congress Centre, a 150 year old former custom's house located in the historic centre of Porto on the bank of the river Douro. The venue was renovated by a Pritzer prize winning architect and has received many awards. LOCAL ORGANISER: José Nuno Oliveira University of Minho, Portugal For any queries about local issues please contact the local organiser, José Nuno Oliveira . ====================================================================== This message and any attachment are intended solely for the addressee and may contain confidential information. If you have received this message in error, please contact the sender and delete the email and attachment. Any views or opinions expressed by the author of this email do not necessarily reflect the views of the University of Nottingham. Email communications with the University of Nottingham may be monitored where permitted by law. From david.feuer at gmail.com Mon Aug 19 10:14:20 2019 From: david.feuer at gmail.com (David Feuer) Date: Mon, 19 Aug 2019 17:14:20 +0700 Subject: [Haskell-cafe] Unfolding alongside folding Message-ID: Thinking about fusing indexed maps for lists led me to consider the following function, which generalizes mapWithIndex to allow arbitrary stateful computation foldWithUnfold :: (a -> s -> Maybe (b, s)) -> [a] -> s -> [b] foldWithUnfold f = go where go (a : as) s | Just (b, s') <- f a s = b : go as s' go _ _ = [] which we can fit into fold/build fusion like so: foldWithUnfold f as s0 = build $ \c n -> let go a k s | Just (b, s') <- f a s = b `c` k s' | otherwise = n in foldr go (const n) as s0 Does a function of this general nature exist in some package already? Also, I see that the type can be expressed foldWithUnfoldS :: (a -> StateT s Maybe b) -> [a] -> s -> [b] Is that a better or worse way to say it? -------------- next part -------------- An HTML attachment was scrubbed... URL: From francesquini at gmail.com Mon Aug 19 12:14:05 2019 From: francesquini at gmail.com (Emilio Francesquini) Date: Mon, 19 Aug 2019 09:14:05 -0300 Subject: [Haskell-cafe] Optimizations for list comprehension Message-ID: Hello Cafe, While investigating a performance problem I stumbled upon what I eventually reduced to the example below: module Main where import Data.Time.Clock outside :: Int -> Int outside n = sum [i + j | i <- range, j <- range] where range = [0..n-1] inside :: Int -> Int inside n = sum [i + j | i <- [0..n-1], j <- [0..n-1]] main :: IO () main = do t0 <- getCurrentTime print $ inside 10000 t1 <- getCurrentTime print $ outside 10000 t2 <-getCurrentTime print (diffUTCTime t1 t0) print (diffUTCTime t2 t1) Compiling with -O2, up to GHC 8.2.2, both `inside` and `outside` functions would take the same amount of time to execute. Somewhere between GHC 8.2.2 and 8.6.4 something changed (possibly some new optimization) making `inside` run ~4x faster on my machine. With LLVM the difference is even bigger. It is not that `outside` got slower, but that `inside` got much faster. I'm curious to what optimizations might be happening to the `inside` function that would not fire on the outside function. Any hints? Best regards, Emilio -------------- next part -------------- An HTML attachment was scrubbed... URL: From capn.freako at gmail.com Mon Aug 19 14:02:30 2019 From: capn.freako at gmail.com (David Banas) Date: Mon, 19 Aug 2019 07:02:30 -0700 Subject: [Haskell-cafe] Unfolding alongside folding In-Reply-To: References: Message-ID: <209CFA1F-1F58-4697-A334-94DE39FE71FE@gmail.com> I’m not certain, but think you might be describing hylomorphism: https://medium.com/@JosephJnk/hylomorphisms-43a5494729b7 -db > On Aug 19, 2019, at 5:00 AM, haskell-cafe-request at haskell.org wrote: > > Does a function of this general nature exist in some package already? -------------- next part -------------- An HTML attachment was scrubbed... URL: From will.yager at gmail.com Mon Aug 19 14:34:42 2019 From: will.yager at gmail.com (William Yager) Date: Mon, 19 Aug 2019 22:34:42 +0800 Subject: [Haskell-cafe] Optimizations for list comprehension In-Reply-To: References: Message-ID: I'm not sure which exact optimizations are responsible, but based on --ddump-simple, * "inside" is not allocating any lists at all. It's just a couple loops over unboxed ints * "outside" is actually allocating a (single) list data structure and has an inner loop and an outer loop, both of which traverse the list GHC seems to be too aggressive about sharing "range" in "outside". Adding a unit argument to "range" makes both functions go fast. On Mon, Aug 19, 2019 at 8:14 PM Emilio Francesquini wrote: > Hello Cafe, > > While investigating a performance problem I stumbled upon what I > eventually reduced to the example below: > > module Main where > > import Data.Time.Clock > > outside :: Int -> Int > outside n = > sum [i + j | i <- range, j <- range] > where > range = [0..n-1] > > inside :: Int -> Int > inside n = > sum [i + j | i <- [0..n-1], j <- [0..n-1]] > > main :: IO () > main = do > t0 <- getCurrentTime > print $ inside 10000 > t1 <- getCurrentTime > print $ outside 10000 > t2 <-getCurrentTime > > print (diffUTCTime t1 t0) > print (diffUTCTime t2 t1) > > Compiling with -O2, up to GHC 8.2.2, both `inside` and `outside` functions > would take the same amount of time to execute. Somewhere between GHC 8.2.2 > and 8.6.4 something changed (possibly some new optimization) making > `inside` run ~4x faster on my machine. With LLVM the difference is even > bigger. > > It is not that `outside` got slower, but that `inside` got much faster. > I'm curious to what optimizations might be happening to the `inside` > function that would not fire on the outside function. > > Any hints? > > Best regards, > > Emilio > > > > > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -------------- next part -------------- An HTML attachment was scrubbed... URL: From meng.wang at bristol.ac.uk Mon Aug 19 16:32:19 2019 From: meng.wang at bristol.ac.uk (Meng Wang) Date: Mon, 19 Aug 2019 16:32:19 +0000 Subject: [Haskell-cafe] Permenent Faculty Position in PL at University of Bristol Message-ID: <2F9C9046-AA48-4297-8DE9-760911A32E5A@bristol.ac.uk> Dear Haskellers, As part of a strategic expansion, the Department of Computer Science at the University of Bristol is hiring in the area of programming languages at the Lecturer (Assistant Professor) or Senior Lecturer/Reader (Associate Professor) level: http://www.bristol.ac.uk/jobs/find/details.html?nPostingID=51136&nPostingTargetID=156814&option=28&sort=DESC&respnr=2&ID=Q50FK026203F3VBQBV7V77V83&Resultsperpage=10&lg=UK&mask=uobext Applications in the area of functional programming are especially encouraged. The deadline for application is 8 September 2019. Best wishes, Meng Wang, PhD Senior Lecturer (Associate Professor) Department of Computer Science University of Bristol Merchant Venturers Building, Woodland Road, Clifton BS8 1UB +44 (0) 117 954 5145 meng.wang at bristol.ac.uk -------------- next part -------------- An HTML attachment was scrubbed... URL: From chrisdone at gmail.com Tue Aug 20 16:36:23 2019 From: chrisdone at gmail.com (Christopher Done) Date: Tue, 20 Aug 2019 17:36:23 +0100 Subject: [Haskell-cafe] Getting both the value and name of a variable in one expression Message-ID: Hi all, Do we have already a syntax for ‘foo that also contains the typed value like TExp? I have e.g. an AST that I want to do more static checks on it that aren’t as convenient to do in the type system. Here’s an example: -- | Check the grammar spec to produce a grammar.checkGrammar :: (SchemaName, [(SchemaName, Schema)]) -> Q ExpcheckGrammar (toplevel, rules) = if M.size rulesMap /= length rules then error "Duplicate rule names in grammar." else lift (Grammar {grammarToplevel = toplevel, grammarRules = rulesMap}) where rulesMap = M.fromList rules -- | Grammar for Haskell.grammar :: Grammargrammar = $(checkGrammar $ runDefine $ mdo -- General expression expression <- rule "Expression" (ChoiceSchema [variable, constructor, parentheses ,tuple, let', application, string]) application <- rule "Application" (CompositeSchema [expression, expression]) parentheses <- rule "Parentheses" (CompositeSchema [openParenSchema, expression, closeParenSchema]) ... pure expression) Here I do a trivial check for duplicates. After I’ve checked the expression at compile-time, I Lift it so that it can be used at runtime. That’s pretty good. But some types like (a -> b) don’t Lift. So an alternative would be: grammar = $(checkGrammar_take2 thename 'thename) In which checkGrammar_take2 would: 1. Use thename at compile-time for a check. 2. If the check passes, then return (VarE thename) E.g. checkGrammar_take2 value name = if valueFine value then varE name elseerror "value isn't fine" That’s actually quite a good solution because it avoids a lift, and I didn’t transform the AST. It’s also more efficient than lifting. But there’s no checked relationship between thename and ‘thename. checkGrammar_take2 has no way of knowing that they refer to the same thing. See? Hence, if I could get e.g. `thename to produce both the value and a name for the value, that would be cool. My gist doesn’t go this far. It might look like this: checkGrammar_take2 namedValue = if valueFine (getValue namedValue) then getExp namedValue else error "value isn't fine" and call it like: mygrammar = checkGrammar_take2 `thename So the semantics would be roughly similar to [|| thename ||] :: TExp a but you’d get `thename :: Named a where data Named a = { namedThing :: a, nameOfThing :: Name } I feel like the more DSLs I design, the more I’d like something like this to perform my static checks. Cheers, Chris -------------- next part -------------- An HTML attachment was scrubbed... URL: From francesquini at gmail.com Tue Aug 20 19:12:51 2019 From: francesquini at gmail.com (Emilio Francesquini) Date: Tue, 20 Aug 2019 16:12:51 -0300 Subject: [Haskell-cafe] Optimizations for list comprehension In-Reply-To: References: Message-ID: Thanks William! For me it's quite unexpected to see a unit argument making that kind of difference for the optimizer... Anyway, one new trick added to the bag... Tks. On Mon, Aug 19, 2019 at 11:34 AM William Yager wrote: > I'm not sure which exact optimizations are responsible, but based on > --ddump-simple, > > * "inside" is not allocating any lists at all. It's just a couple loops > over unboxed ints > * "outside" is actually allocating a (single) list data structure and has > an inner loop and an outer loop, both of which traverse the list > > GHC seems to be too aggressive about sharing "range" in "outside". Adding > a unit argument to "range" makes both functions go fast. > > On Mon, Aug 19, 2019 at 8:14 PM Emilio Francesquini < > francesquini at gmail.com> wrote: > >> Hello Cafe, >> >> While investigating a performance problem I stumbled upon what I >> eventually reduced to the example below: >> >> module Main where >> >> import Data.Time.Clock >> >> outside :: Int -> Int >> outside n = >> sum [i + j | i <- range, j <- range] >> where >> range = [0..n-1] >> >> inside :: Int -> Int >> inside n = >> sum [i + j | i <- [0..n-1], j <- [0..n-1]] >> >> main :: IO () >> main = do >> t0 <- getCurrentTime >> print $ inside 10000 >> t1 <- getCurrentTime >> print $ outside 10000 >> t2 <-getCurrentTime >> >> print (diffUTCTime t1 t0) >> print (diffUTCTime t2 t1) >> >> Compiling with -O2, up to GHC 8.2.2, both `inside` and `outside` >> functions would take the same amount of time to execute. Somewhere between >> GHC 8.2.2 and 8.6.4 something changed (possibly some new optimization) >> making `inside` run ~4x faster on my machine. With LLVM the difference is >> even bigger. >> >> It is not that `outside` got slower, but that `inside` got much faster. >> I'm curious to what optimizations might be happening to the `inside` >> function that would not fire on the outside function. >> >> Any hints? >> >> Best regards, >> >> Emilio >> >> >> >> >> _______________________________________________ >> Haskell-Cafe mailing list >> To (un)subscribe, modify options or view archives go to: >> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >> Only members subscribed via the mailman list are allowed to post. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From sylvain at haskus.fr Wed Aug 21 13:09:15 2019 From: sylvain at haskus.fr (Sylvain Henry) Date: Wed, 21 Aug 2019 15:09:15 +0200 Subject: [Haskell-cafe] Question on inductive type-families Message-ID: <855bef4f-071a-e47c-e89c-a0d0b23a76e1@haskus.fr> Hi, Suppose I have the following type family: type family Index (n :: Nat) (l :: [k]) = (r :: k) where    Index 0 (x ': _ ) = x    Index n (_ ': xs) = Index (n-1) xs I'm using it to define a Variant type: data V2 (vs :: [k]) where    V2 :: forall vs (n :: Nat). KnownNat n => Proxy n -> Index n vs -> V2 vs Now I want to match on the Variant retrieving either the head or the tail (another Variant): splitV2 :: forall v vs. V2 (v:vs) -> Either v (V2 vs) splitV2 = \case    V2 (n1 :: Proxy n) v -> case sameNat n1 (Proxy @0) of          Just Refl -> Left v          Nothing   -> Right (V2 (Proxy @(n-1)) v) It fails to typecheck with: Couldn't match type ‘Index n (v : vs)’ with ‘Index (n - 1) vs’ Expected type: Index (n - 1) vs Actual type: Index n vs1 NB: ‘Index’ is a non-injective type family Is there a way to make this work? This is highly speculative as I'm not very familiar with type-checking: would it be sound to make the inductive Index family "weakly" injective? I.e. somehow produce a typing rule for the type family:   forall n n' x xs xs'.     Solving: Index n (x ': xs) ~ Index (n'-1) xs'     Is equivalent to solving: if n /= 0 then (n ~ n', xs ~ xs') else (x ~ Index (n'-1) xs') Here we could know that "n /= 0" thanks to the match on "sameNat n1 (Proxy @0)". ("weakly" because we have some form of injectivity on the shape of the list but not on its contents) Any pointer on this kind of stuff in research papers, Coq, Agda, etc. ? Thanks, Sylvain From mail at nh2.me Wed Aug 21 13:28:01 2019 From: mail at nh2.me (=?UTF-8?Q?Niklas_Hamb=c3=bcchen?=) Date: Wed, 21 Aug 2019 15:28:01 +0200 Subject: [Haskell-cafe] Optimizations for list comprehension In-Reply-To: References: Message-ID: <57e8b629-3417-a4ae-5a19-8b40195e9f0e@nh2.me> Please file a GHC issue for this, to avoid that Haskell gets slower over time :) On 20/08/2019 21:12, Emilio Francesquini wrote: > For me it's quite unexpected to see a unit argument making that kind of difference for the optimizer... > > Anyway, one new trick added to the bag... From claude at mathr.co.uk Wed Aug 21 13:45:49 2019 From: claude at mathr.co.uk (Claude Heiland-Allen) Date: Wed, 21 Aug 2019 14:45:49 +0100 Subject: [Haskell-cafe] Optimizations for list comprehension In-Reply-To: References: Message-ID: <1d56916c-cf9d-21ac-68a9-52a152c4de7c@mathr.co.uk> Hi, On 20/08/2019 20:12, Emilio Francesquini wrote: > Thanks William! > > For me it's quite unexpected to see a unit argument making that kind > of difference for the optimizer... > > Anyway, one new trick added to the bag... > > Tks. > > > > On Mon, Aug 19, 2019 at 11:34 AM William Yager > wrote: > > I'm not sure which exact optimizations are responsible, but based > on --ddump-simple, > > * "inside" is not allocating any lists at all. It's just a couple > loops over unboxed ints > * "outside" is actually allocating a (single) list data structure > and has an inner loop and an outer loop, both of which traverse > the list > > GHC seems to be too aggressive about sharing "range" in "outside". > Adding a unit argument to "range" makes both functions go fast. > In "outside", "range" is a single (monomorphic) CAF binding, so I would expect it to be shared aggressively. Even if you do something like "inside" with explicit naming: inside2 :: Int -> Int inside2 n =   sum [i + j | i <- range1, j <- range2]   where     range1 = [0..n-1]     range2 = [0..n-1] then "range2" is shared between all iterations over "range1", which I expect to be allocated and traversed.  I haven't tested to be sure. Historically I have used crass hacks to prevent sharing by introducing data dependencies: inside3 :: Int -> Int inside3 n =   sum [i + j | i <- [0..n-1], j <- [i+0-i..n-1]] That "inside" can be optimized to avoid allocations of the inner loop is a pleasant surprise, I hope it doesn't lead to unpleasant surprises in other circumstances. > > On Mon, Aug 19, 2019 at 8:14 PM Emilio Francesquini > > wrote: > > Hello Cafe, > > While investigating a performance problem I stumbled upon what > I eventually reduced to the example below: > > module Main where > > import Data.Time.Clock > > outside :: Int -> Int > outside n = >   sum [i + j | i <- range, j <- range] >   where >     range = [0..n-1] > > inside :: Int -> Int > inside n = >   sum [i + j | i <- [0..n-1], j <- [0..n-1]] > > main :: IO () > main = do >   t0 <- getCurrentTime >   print $ inside 10000 >   t1 <- getCurrentTime >   print $ outside 10000 >   t2 <-getCurrentTime > >   print (diffUTCTime t1 t0) >   print (diffUTCTime t2 t1) > > Compiling with -O2, up to GHC 8.2.2, both `inside` and > `outside` functions would take the same amount of time to > execute. Somewhere between GHC 8.2.2 and 8.6.4 something > changed (possibly some new optimization) making `inside` run > ~4x faster on my machine. With LLVM the difference is even bigger. > > It is not that `outside` got slower, but that `inside` got > much faster. I'm curious to what optimizations might be > happening to the `inside` function that would not fire on the > outside function. > > Any hints? > Claude -- https://mathr.co.uk From lysxia at gmail.com Wed Aug 21 14:46:25 2019 From: lysxia at gmail.com (Li-yao Xia) Date: Wed, 21 Aug 2019 10:46:25 -0400 Subject: [Haskell-cafe] Question on inductive type-families In-Reply-To: <855bef4f-071a-e47c-e89c-a0d0b23a76e1@haskus.fr> References: <855bef4f-071a-e47c-e89c-a0d0b23a76e1@haskus.fr> Message-ID: <159641df-6a6a-45b7-3618-b80b3489d5f0@gmail.com> Hi Sylvain, The problem is that in the case where `n1` is not equal to `0`, this unequality is not made available as a constraint solver (whereas in the case where they are equal, the `Refl` constructor makes the corresponding equality constraint available). In fact, there is no built-in "unequality constraint" that acts as a counterpart to `~` (it does not seem quite straightforward how that would even work), but there is one way to encode it as a boolean type family `((n == 0) ~ 'False)`. That requires changing type families to pattern-match on `n == 0` instead of `n` directly, and possibly additional gymnastics to reflect the comparison at term-level: type Index n l = IndexIf (n == 0) n l type family IndexIf (b :: Bool) (n :: Nat) (l :: [k]) :: k where IndexIf 'False n (x ': _ ) = x IndexIf 'True n (_ ': xs) = Index (n - 1) xs Cheers, Li-yao On 8/21/19 9:09 AM, Sylvain Henry wrote: > Hi, > > Suppose I have the following type family: > > type family Index (n :: Nat) (l :: [k]) = (r :: k) where >    Index 0 (x ': _ ) = x >    Index n (_ ': xs) = Index (n-1) xs > > I'm using it to define a Variant type: > > data V2 (vs :: [k]) where >    V2 :: forall vs (n :: Nat). KnownNat n => Proxy n -> Index n vs -> > V2 vs > > Now I want to match on the Variant retrieving either the head or the > tail (another Variant): > > splitV2 :: forall v vs. V2 (v:vs) -> Either v (V2 vs) > splitV2 = \case >    V2 (n1 :: Proxy n) v -> case sameNat n1 (Proxy @0) of >          Just Refl -> Left v >          Nothing   -> Right (V2 (Proxy @(n-1)) v) > > It fails to typecheck with: > > Couldn't match type ‘Index n (v : vs)’ with ‘Index (n - 1) vs’ > Expected type: Index (n - 1) vs > Actual type: Index n vs1 > NB: ‘Index’ is a non-injective type family > > > Is there a way to make this work? > > > This is highly speculative as I'm not very familiar with type-checking: > would it be sound to make the inductive Index family "weakly" injective? > I.e. somehow produce a typing rule for the type family: > >   forall n n' x xs xs'. >     Solving: Index n (x ': xs) ~ Index (n'-1) xs' >     Is equivalent to solving: if n /= 0 then (n ~ n', xs ~ xs') else (x > ~ Index (n'-1) xs') > > Here we could know that "n /= 0" thanks to the match on "sameNat n1 > (Proxy @0)". > > ("weakly" because we have some form of injectivity on the shape of the > list but not on its contents) > > Any pointer on this kind of stuff in research papers, Coq, Agda, etc. ? > > Thanks, > Sylvain > > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. From simonpj at microsoft.com Wed Aug 21 15:47:58 2019 From: simonpj at microsoft.com (Simon Peyton Jones) Date: Wed, 21 Aug 2019 15:47:58 +0000 Subject: [Haskell-cafe] Optimizations for list comprehension In-Reply-To: References: Message-ID: I think what is happening is that * In “inside” there are two distinct lists [0..n-1], each used once; they are fused with their consumers. * In “outside” there is one list [0..n-1], which is used twice. GHC is paranoid about duplicating work (and would be right to do so if producing the list was expensive), so it does not fuse the list with its two consumers. In this case GHC’s paranoia is not justified. It’d be better to duplicate the production of [0..n-1] so that it can fuse with its consumers. One way to address this problem might be “cheapBuild”. There’s a ticket about this: https://gitlab.haskell.org/ghc/ghc/issues/7206. I see that a year ago the TL;DR was “Conclusion: let's do it. Ensuring that a Note gives a clear explanation, and points to this ticket.” But no one yet has. Maybe someone might see if the cheapBuild idea really does solve this particular case. Simon From: Haskell-Cafe On Behalf Of William Yager Sent: 19 August 2019 15:35 To: Emilio Francesquini Cc: Haskell Cafe Subject: Re: [Haskell-cafe] Optimizations for list comprehension I'm not sure which exact optimizations are responsible, but based on --ddump-simple, * "inside" is not allocating any lists at all. It's just a couple loops over unboxed ints * "outside" is actually allocating a (single) list data structure and has an inner loop and an outer loop, both of which traverse the list GHC seems to be too aggressive about sharing "range" in "outside". Adding a unit argument to "range" makes both functions go fast. On Mon, Aug 19, 2019 at 8:14 PM Emilio Francesquini > wrote: Hello Cafe, While investigating a performance problem I stumbled upon what I eventually reduced to the example below: module Main where import Data.Time.Clock outside :: Int -> Int outside n = sum [i + j | i <- range, j <- range] where range = [0..n-1] inside :: Int -> Int inside n = sum [i + j | i <- [0..n-1], j <- [0..n-1]] main :: IO () main = do t0 <- getCurrentTime print $ inside 10000 t1 <- getCurrentTime print $ outside 10000 t2 <-getCurrentTime print (diffUTCTime t1 t0) print (diffUTCTime t2 t1) Compiling with -O2, up to GHC 8.2.2, both `inside` and `outside` functions would take the same amount of time to execute. Somewhere between GHC 8.2.2 and 8.6.4 something changed (possibly some new optimization) making `inside` run ~4x faster on my machine. With LLVM the difference is even bigger. It is not that `outside` got slower, but that `inside` got much faster. I'm curious to what optimizations might be happening to the `inside` function that would not fire on the outside function. Any hints? Best regards, Emilio _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Wed Aug 21 16:31:08 2019 From: mgsloan at gmail.com (Michael Sloan) Date: Wed, 21 Aug 2019 10:31:08 -0600 Subject: [Haskell-cafe] Getting both the value and name of a variable in one expression In-Reply-To: References: Message-ID: One potential solution here is to have checkGrammar_take2 return an expression which returns an expression. I haven't tried compiling this, but something roughly like: checkGrammar_2 name = [| if valueFine $(varE name) then varE name else error "value isn't fine" |] Then it'd be used like $($(checkGrammar_2 'thename)). The th-orphans package can also be useful for this because it provides Lift instances for the TH AST. -Michael On Tue, Aug 20, 2019 at 10:36 AM Christopher Done wrote: > > Hi all, > > Do we have already a syntax for ‘foo that also contains the typed value like TExp? > > I have e.g. an AST that I want to do more static checks on it that aren’t as convenient to do in the type system. Here’s an example: > > -- | Check the grammar spec to produce a grammar. > checkGrammar :: (SchemaName, [(SchemaName, Schema)]) -> Q Exp > checkGrammar (toplevel, rules) = > if M.size rulesMap /= length rules > then error "Duplicate rule names in grammar." > else lift (Grammar {grammarToplevel = toplevel, grammarRules = rulesMap}) > where > rulesMap = M.fromList rules > > -- | Grammar for Haskell. > grammar :: Grammar > grammar = $(checkGrammar $ runDefine $ mdo > -- General expression > expression <- rule "Expression" (ChoiceSchema [variable, constructor, parentheses > ,tuple, let', application, string]) > application <- rule "Application" (CompositeSchema [expression, expression]) > parentheses <- rule "Parentheses" (CompositeSchema [openParenSchema, expression, closeParenSchema]) > > ... > pure expression) > > Here I do a trivial check for duplicates. After I’ve checked the > expression at compile-time, I Lift it so that it can be used at > runtime. That’s pretty good. But some types like (a -> b) don’t Lift. So > an alternative would be: > > grammar = $(checkGrammar_take2 thename 'thename) > > In which checkGrammar_take2 would: > > Use thename at compile-time for a check. > If the check passes, then return (VarE thename) > > E.g. > > checkGrammar_take2 value name = if valueFine value then varE name else > error "value isn't fine" > > That’s actually quite a good solution because it avoids a lift, and I > didn’t transform the AST. It’s also more efficient than lifting. > > But there’s no checked relationship between thename and ‘thename. > checkGrammar_take2 has no way of knowing that they refer to the same > thing. See? > > Hence, if I could get e.g. `thename to produce both the value and a > name for the value, that would be cool. My gist doesn’t go this > far. It might look like this: > > checkGrammar_take2 namedValue = if valueFine (getValue namedValue) then getExp namedValue else error "value isn't fine" > > and call it like: > > mygrammar = checkGrammar_take2 `thename > > So the semantics would be roughly similar to > > [|| thename ||] :: TExp a > > but you’d get > > `thename :: Named a > > where > > data Named a = { namedThing :: a, nameOfThing :: Name } > > I feel like the more DSLs I design, the more I’d like something like this to perform my static checks. > > Cheers, > > Chris > > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. From sylvain at haskus.fr Thu Aug 22 08:33:32 2019 From: sylvain at haskus.fr (Sylvain Henry) Date: Thu, 22 Aug 2019 10:33:32 +0200 Subject: [Haskell-cafe] Question on inductive type-families In-Reply-To: <159641df-6a6a-45b7-3618-b80b3489d5f0@gmail.com> References: <855bef4f-071a-e47c-e89c-a0d0b23a76e1@haskus.fr> <159641df-6a6a-45b7-3618-b80b3489d5f0@gmail.com> Message-ID: <5f958804-f272-a9da-f790-622e262a1069@haskus.fr> Hi Li-yao, Thanks for your answer. Sadly I haven't managed to make it work this way neither. In addition I need a "KnownNat (n-1)" while I only have "KnownNat n" (and the knowledge that n > 0). For the record, it works with an unsafeCoerce: data V2 (vs :: [k]) where     V2 :: forall vs (n :: Nat). KnownNat n => Proxy n -> Index n vs -> V2 vs splitV2 :: forall v vs. V2 (v:vs) -> Either (V2 vs) v {-# INLINE splitV2 #-} splitV2 = \case     V2 (n1 :: Proxy n) v -> case sameNat n1 (Proxy @0) of        Just Refl -> Right v        Nothing   -> case someNatVal (natVal n1 - 1) of          SomeNat (n2 :: Proxy n') -> case unsafeCoerce Refl :: Index n (v:vs) :~: Index n' vs of             Refl -> Left (V2 n2 v) instance Show (V2 '[]) where    {-# INLINABLE show #-}    show = undefined instance (Show x, Show (V2 xs)) => Show (V2 (x ': xs)) where    {-# INLINABLE show #-}    show v = case splitV2 v of       Right x -> show x       Left xs -> show xs test :: V2 '[Int,Word,String] -> String test v = show v However the generated Core isn't as pretty as with the previous representation (which uses unsafeCoerce for the value, not for the index): data Variant (types :: [*]) = Variant {-# UNPACK #-} !Word Any I'll stick to this one for now. Sylvain On 21/08/2019 16:46, Li-yao Xia wrote: > Hi Sylvain, > > The problem is that in the case where `n1` is not equal to `0`, this > unequality is not made available as a constraint solver (whereas in > the case where they are equal, the `Refl` constructor makes the > corresponding equality constraint available). > > In fact, there is no built-in "unequality constraint" that acts as a > counterpart to `~` (it does not seem quite straightforward how that > would even work), but there is one way to encode it as a boolean type > family `((n == 0) ~ 'False)`. That requires changing type families to > pattern-match on `n == 0` instead of `n` directly, and possibly > additional gymnastics to reflect the comparison at term-level: > > > type Index n l = IndexIf (n == 0) n l > > type family IndexIf (b :: Bool) (n :: Nat) (l :: [k]) :: k where >   IndexIf 'False n (x ': _ ) = x >   IndexIf 'True  n (_ ': xs) = Index (n - 1) xs > > > Cheers, > Li-yao > > On 8/21/19 9:09 AM, Sylvain Henry wrote: >> Hi, >> >> Suppose I have the following type family: >> >> type family Index (n :: Nat) (l :: [k]) = (r :: k) where >>     Index 0 (x ': _ ) = x >>     Index n (_ ': xs) = Index (n-1) xs >> >> I'm using it to define a Variant type: >> >> data V2 (vs :: [k]) where >>     V2 :: forall vs (n :: Nat). KnownNat n => Proxy n -> Index n vs >> -> V2 vs >> >> Now I want to match on the Variant retrieving either the head or the >> tail (another Variant): >> >> splitV2 :: forall v vs. V2 (v:vs) -> Either v (V2 vs) >> splitV2 = \case >>     V2 (n1 :: Proxy n) v -> case sameNat n1 (Proxy @0) of >>           Just Refl -> Left v >>           Nothing   -> Right (V2 (Proxy @(n-1)) v) >> >> It fails to typecheck with: >> >> Couldn't match type ‘Index n (v : vs)’ with ‘Index (n - 1) vs’ >> Expected type: Index (n - 1) vs >> Actual type: Index n vs1 >> NB: ‘Index’ is a non-injective type family >> >> >> Is there a way to make this work? >> >> >> This is highly speculative as I'm not very familiar with >> type-checking: would it be sound to make the inductive Index family >> "weakly" injective? I.e. somehow produce a typing rule for the type >> family: >> >>    forall n n' x xs xs'. >>      Solving: Index n (x ': xs) ~ Index (n'-1) xs' >>      Is equivalent to solving: if n /= 0 then (n ~ n', xs ~ xs') else >> (x ~ Index (n'-1) xs') >> >> Here we could know that "n /= 0" thanks to the match on "sameNat n1 >> (Proxy @0)". >> >> ("weakly" because we have some form of injectivity on the shape of >> the list but not on its contents) >> >> Any pointer on this kind of stuff in research papers, Coq, Agda, etc. ? >> >> Thanks, >> Sylvain >> >> _______________________________________________ >> Haskell-Cafe mailing list >> To (un)subscribe, modify options or view archives go to: >> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >> Only members subscribed via the mailman list are allowed to post. -------------- next part -------------- An HTML attachment was scrubbed... URL: From allbery.b at gmail.com Thu Aug 22 10:16:39 2019 From: allbery.b at gmail.com (Brandon Allbery) Date: Thu, 22 Aug 2019 06:16:39 -0400 Subject: [Haskell-cafe] Question on inductive type-families In-Reply-To: <5f958804-f272-a9da-f790-622e262a1069@haskus.fr> References: <855bef4f-071a-e47c-e89c-a0d0b23a76e1@haskus.fr> <159641df-6a6a-45b7-3618-b80b3489d5f0@gmail.com> <5f958804-f272-a9da-f790-622e262a1069@haskus.fr> Message-ID: There are some plugins like natnormalise that help with this kind of thing. ghc itself is not so good at these kinds of deductions. On Thu, Aug 22, 2019 at 4:33 AM Sylvain Henry wrote: > Hi Li-yao, > > Thanks for your answer. Sadly I haven't managed to make it work this way > neither. > > In addition I need a "KnownNat (n-1)" while I only have "KnownNat n" (and > the knowledge that n > 0). For the record, it works with an unsafeCoerce: > > data V2 (vs :: [k]) where > V2 :: forall vs (n :: Nat). KnownNat n => Proxy n -> Index n vs -> V2 > vs > > splitV2 :: forall v vs. V2 (v:vs) -> Either (V2 vs) v > {-# INLINE splitV2 #-} > splitV2 = \case > V2 (n1 :: Proxy n) v -> case sameNat n1 (Proxy @0) of > Just Refl -> Right v > Nothing -> case someNatVal (natVal n1 - 1) of > SomeNat (n2 :: Proxy n') -> case unsafeCoerce Refl :: Index n > (v:vs) :~: Index n' vs of > Refl -> Left (V2 n2 v) > > instance Show (V2 '[]) where > {-# INLINABLE show #-} > show = undefined > > instance (Show x, Show (V2 xs)) => Show (V2 (x ': xs)) where > {-# INLINABLE show #-} > show v = case splitV2 v of > Right x -> show x > Left xs -> show xs > > test :: V2 '[Int,Word,String] -> String > test v = show v > > However the generated Core isn't as pretty as with the previous > representation (which uses unsafeCoerce for the value, not for the index): > > data Variant (types :: [*]) = Variant {-# UNPACK #-} !Word Any > > > I'll stick to this one for now. > > Sylvain > > > On 21/08/2019 16:46, Li-yao Xia wrote: > > Hi Sylvain, > > The problem is that in the case where `n1` is not equal to `0`, this > unequality is not made available as a constraint solver (whereas in the > case where they are equal, the `Refl` constructor makes the corresponding > equality constraint available). > > In fact, there is no built-in "unequality constraint" that acts as a > counterpart to `~` (it does not seem quite straightforward how that would > even work), but there is one way to encode it as a boolean type family `((n > == 0) ~ 'False)`. That requires changing type families to pattern-match on > `n == 0` instead of `n` directly, and possibly additional gymnastics to > reflect the comparison at term-level: > > > type Index n l = IndexIf (n == 0) n l > > type family IndexIf (b :: Bool) (n :: Nat) (l :: [k]) :: k where > IndexIf 'False n (x ': _ ) = x > IndexIf 'True n (_ ': xs) = Index (n - 1) xs > > > Cheers, > Li-yao > > On 8/21/19 9:09 AM, Sylvain Henry wrote: > > Hi, > > Suppose I have the following type family: > > type family Index (n :: Nat) (l :: [k]) = (r :: k) where > Index 0 (x ': _ ) = x > Index n (_ ': xs) = Index (n-1) xs > > I'm using it to define a Variant type: > > data V2 (vs :: [k]) where > V2 :: forall vs (n :: Nat). KnownNat n => Proxy n -> Index n vs -> V2 > vs > > Now I want to match on the Variant retrieving either the head or the tail > (another Variant): > > splitV2 :: forall v vs. V2 (v:vs) -> Either v (V2 vs) > splitV2 = \case > V2 (n1 :: Proxy n) v -> case sameNat n1 (Proxy @0) of > Just Refl -> Left v > Nothing -> Right (V2 (Proxy @(n-1)) v) > > It fails to typecheck with: > > Couldn't match type ‘Index n (v : vs)’ with ‘Index (n - 1) vs’ > Expected type: Index (n - 1) vs > Actual type: Index n vs1 > NB: ‘Index’ is a non-injective type family > > > Is there a way to make this work? > > > This is highly speculative as I'm not very familiar with type-checking: > would it be sound to make the inductive Index family "weakly" injective? > I.e. somehow produce a typing rule for the type family: > > forall n n' x xs xs'. > Solving: Index n (x ': xs) ~ Index (n'-1) xs' > Is equivalent to solving: if n /= 0 then (n ~ n', xs ~ xs') else (x ~ > Index (n'-1) xs') > > Here we could know that "n /= 0" thanks to the match on "sameNat n1 (Proxy > @0)". > > ("weakly" because we have some form of injectivity on the shape of the > list but not on its contents) > > Any pointer on this kind of stuff in research papers, Coq, Agda, etc. ? > > Thanks, > Sylvain > > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. > > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -- brandon s allbery kf8nh allbery.b at gmail.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From chrisdone at gmail.com Thu Aug 22 15:26:17 2019 From: chrisdone at gmail.com (Christopher Done) Date: Thu, 22 Aug 2019 16:26:17 +0100 Subject: [Haskell-cafe] Getting both the value and name of a variable in one expression In-Reply-To: References: Message-ID: I considered an expression-within-an-expression but thought a stage-restriction would break it. Maybe not! Let me go test it! On Wed, 21 Aug 2019 at 17:31, Michael Sloan wrote: > One potential solution here is to have checkGrammar_take2 return an > expression which returns an expression. I haven't tried compiling > this, but something roughly like: > > checkGrammar_2 name = [| if valueFine $(varE name) then varE name else > error "value isn't fine" |] > > Then it'd be used like $($(checkGrammar_2 'thename)). The th-orphans > package can also be useful for this because it provides Lift instances > for the TH AST. > > -Michael > > On Tue, Aug 20, 2019 at 10:36 AM Christopher Done > wrote: > > > > Hi all, > > > > Do we have already a syntax for ‘foo that also contains the typed value > like TExp? > > > > I have e.g. an AST that I want to do more static checks on it that > aren’t as convenient to do in the type system. Here’s an example: > > > > -- | Check the grammar spec to produce a grammar. > > checkGrammar :: (SchemaName, [(SchemaName, Schema)]) -> Q Exp > > checkGrammar (toplevel, rules) = > > if M.size rulesMap /= length rules > > then error "Duplicate rule names in grammar." > > else lift (Grammar {grammarToplevel = toplevel, grammarRules = > rulesMap}) > > where > > rulesMap = M.fromList rules > > > > -- | Grammar for Haskell. > > grammar :: Grammar > > grammar = $(checkGrammar $ runDefine $ mdo > > -- General expression > > expression <- rule "Expression" (ChoiceSchema [variable, > constructor, parentheses > > ,tuple, let', > application, string]) > > application <- rule "Application" (CompositeSchema [expression, > expression]) > > parentheses <- rule "Parentheses" (CompositeSchema > [openParenSchema, expression, closeParenSchema]) > > > > ... > > pure expression) > > > > Here I do a trivial check for duplicates. After I’ve checked the > > expression at compile-time, I Lift it so that it can be used at > > runtime. That’s pretty good. But some types like (a -> b) don’t Lift. So > > an alternative would be: > > > > grammar = $(checkGrammar_take2 thename 'thename) > > > > In which checkGrammar_take2 would: > > > > Use thename at compile-time for a check. > > If the check passes, then return (VarE thename) > > > > E.g. > > > > checkGrammar_take2 value name = if valueFine value then varE name else > > error "value isn't fine" > > > > That’s actually quite a good solution because it avoids a lift, and I > > didn’t transform the AST. It’s also more efficient than lifting. > > > > But there’s no checked relationship between thename and ‘thename. > > checkGrammar_take2 has no way of knowing that they refer to the same > > thing. See? > > > > Hence, if I could get e.g. `thename to produce both the value and a > > name for the value, that would be cool. My gist doesn’t go this > > far. It might look like this: > > > > checkGrammar_take2 namedValue = if valueFine (getValue namedValue) then > getExp namedValue else error "value isn't fine" > > > > and call it like: > > > > mygrammar = checkGrammar_take2 `thename > > > > So the semantics would be roughly similar to > > > > [|| thename ||] :: TExp a > > > > but you’d get > > > > `thename :: Named a > > > > where > > > > data Named a = { namedThing :: a, nameOfThing :: Name } > > > > I feel like the more DSLs I design, the more I’d like something like > this to perform my static checks. > > > > Cheers, > > > > Chris > > > > _______________________________________________ > > Haskell-Cafe mailing list > > To (un)subscribe, modify options or view archives go to: > > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > > Only members subscribed via the mailman list are allowed to post. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chrisdone at gmail.com Thu Aug 22 15:40:34 2019 From: chrisdone at gmail.com (Christopher Done) Date: Thu, 22 Aug 2019 16:40:34 +0100 Subject: [Haskell-cafe] Getting both the value and name of a variable in one expression In-Reply-To: References: Message-ID: Hurray! It works! {-# LANGUAGE TemplateHaskell #-}import Language.Haskell.TH.Syntaximport Language.Haskell.THimport Language.Haskell.TH.Lift () valueFine :: String -> BoolvalueFine = not . null checkGrammar_2 :: Name -> ExpQcheckGrammar_2 name = [| if valueFine $(varE name) then varE name else error "value isn't fine" |] thename :: [Char]thename = "Hello!" thename_empty :: [Char]thename_empty = "" The output: > :t $(checkGrammar_2 'thename) $(checkGrammar_2 'thename) :: ExpQ > :t $($(checkGrammar_2 'thename)) $($(checkGrammar_2 'thename)) :: [Char] > $($(checkGrammar_2 'thename))"Hello!" > $($(checkGrammar_2 'thename_empty)) :49:1: error: • Exception when trying to run compile-time code: value isn't fineCallStack (from HasCallStack): error, called at :49:5 in interactive:Ghci2 Code: (if valueFine thename_empty then varE ((Name (mkOccName "thename_empty")) (((NameG VarName) (mkPkgName "main")) (mkModName "Main"))) else error "value isn't fine") • In the untyped splice: $($(checkGrammar_2 'thename_empty)) Thanks Michael! You’re a star! I should document this in a gist or blog post or something as a technique for DSL checking. On Thu, 22 Aug 2019 at 16:26, Christopher Done wrote: > I considered an expression-within-an-expression but thought a > stage-restriction would break it. Maybe not! Let me go test it! > > On Wed, 21 Aug 2019 at 17:31, Michael Sloan wrote: > >> One potential solution here is to have checkGrammar_take2 return an >> expression which returns an expression. I haven't tried compiling >> this, but something roughly like: >> >> checkGrammar_2 name = [| if valueFine $(varE name) then varE name else >> error "value isn't fine" |] >> >> Then it'd be used like $($(checkGrammar_2 'thename)). The th-orphans >> package can also be useful for this because it provides Lift instances >> for the TH AST. >> >> -Michael >> >> On Tue, Aug 20, 2019 at 10:36 AM Christopher Done >> wrote: >> > >> > Hi all, >> > >> > Do we have already a syntax for ‘foo that also contains the typed value >> like TExp? >> > >> > I have e.g. an AST that I want to do more static checks on it that >> aren’t as convenient to do in the type system. Here’s an example: >> > >> > -- | Check the grammar spec to produce a grammar. >> > checkGrammar :: (SchemaName, [(SchemaName, Schema)]) -> Q Exp >> > checkGrammar (toplevel, rules) = >> > if M.size rulesMap /= length rules >> > then error "Duplicate rule names in grammar." >> > else lift (Grammar {grammarToplevel = toplevel, grammarRules = >> rulesMap}) >> > where >> > rulesMap = M.fromList rules >> > >> > -- | Grammar for Haskell. >> > grammar :: Grammar >> > grammar = $(checkGrammar $ runDefine $ mdo >> > -- General expression >> > expression <- rule "Expression" (ChoiceSchema [variable, >> constructor, parentheses >> > ,tuple, let', >> application, string]) >> > application <- rule "Application" (CompositeSchema [expression, >> expression]) >> > parentheses <- rule "Parentheses" (CompositeSchema >> [openParenSchema, expression, closeParenSchema]) >> > >> > ... >> > pure expression) >> > >> > Here I do a trivial check for duplicates. After I’ve checked the >> > expression at compile-time, I Lift it so that it can be used at >> > runtime. That’s pretty good. But some types like (a -> b) don’t Lift. So >> > an alternative would be: >> > >> > grammar = $(checkGrammar_take2 thename 'thename) >> > >> > In which checkGrammar_take2 would: >> > >> > Use thename at compile-time for a check. >> > If the check passes, then return (VarE thename) >> > >> > E.g. >> > >> > checkGrammar_take2 value name = if valueFine value then varE name else >> > error "value isn't fine" >> > >> > That’s actually quite a good solution because it avoids a lift, and I >> > didn’t transform the AST. It’s also more efficient than lifting. >> > >> > But there’s no checked relationship between thename and ‘thename. >> > checkGrammar_take2 has no way of knowing that they refer to the same >> > thing. See? >> > >> > Hence, if I could get e.g. `thename to produce both the value and a >> > name for the value, that would be cool. My gist doesn’t go this >> > far. It might look like this: >> > >> > checkGrammar_take2 namedValue = if valueFine (getValue namedValue) then >> getExp namedValue else error "value isn't fine" >> > >> > and call it like: >> > >> > mygrammar = checkGrammar_take2 `thename >> > >> > So the semantics would be roughly similar to >> > >> > [|| thename ||] :: TExp a >> > >> > but you’d get >> > >> > `thename :: Named a >> > >> > where >> > >> > data Named a = { namedThing :: a, nameOfThing :: Name } >> > >> > I feel like the more DSLs I design, the more I’d like something like >> this to perform my static checks. >> > >> > Cheers, >> > >> > Chris >> > >> > _______________________________________________ >> > Haskell-Cafe mailing list >> > To (un)subscribe, modify options or view archives go to: >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >> > Only members subscribed via the mailman list are allowed to post. >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chrisdone at gmail.com Thu Aug 22 16:09:06 2019 From: chrisdone at gmail.com (Christopher Done) Date: Thu, 22 Aug 2019 17:09:06 +0100 Subject: [Haskell-cafe] Getting both the value and name of a variable in one expression In-Reply-To: References: Message-ID: Depending on how much syntactic overhead you’re happy with, you can go full type-safe: checkGrammar_3 :: Q (TExp String) -> Q (TExp (Q (TExp String)))checkGrammar_3 q = do TExp expr <- q [|| if valueFine $$(q) then pure (TExp expr) else error "value is not fine" ||] > $$($$(checkGrammar_3 [|| thename ||]))"Hello!" > $$($$(checkGrammar_3 [|| thename_empty ||])) :45:4: error: • Exception when trying to run compile-time code: value is not fine In my case it might even be a fine trade-off, because I’m favoring TH-based validation of a DSL where doing it with e.g. type-level lists and type families has worse type-inference and a higher price to pay in type-signatures. So I can make a “static-smart” constructor that looks more like: checkGrammar_3 :: Q (TExp (Tree a)) -> Q (TExp (Q (TExp (ValidTree a))))useValidTree :: ValidTree a -> ... So you pay the cost once here, but when building the tree, which is more larger code, you don’t pay any cost, and there’s where it matters. On Thu, 22 Aug 2019 at 16:40, Christopher Done wrote: > Hurray! It works! > > {-# LANGUAGE TemplateHaskell #-}import Language.Haskell.TH.Syntaximport Language.Haskell.THimport Language.Haskell.TH.Lift () > valueFine :: String -> BoolvalueFine = not . null > checkGrammar_2 :: Name -> ExpQcheckGrammar_2 name = > [| if valueFine $(varE name) > then varE name > else error "value isn't fine" |] > thename :: [Char]thename = "Hello!" > thename_empty :: [Char]thename_empty = "" > > The output: > > > :t $(checkGrammar_2 'thename) > $(checkGrammar_2 'thename) :: ExpQ > > :t $($(checkGrammar_2 'thename)) > $($(checkGrammar_2 'thename)) :: [Char] > > $($(checkGrammar_2 'thename))"Hello!" > > $($(checkGrammar_2 'thename_empty)) > > :49:1: error: > • Exception when trying to run compile-time code: > value isn't fineCallStack (from HasCallStack): > error, called at :49:5 in interactive:Ghci2 > Code: (if valueFine thename_empty then > varE > ((Name (mkOccName "thename_empty")) > (((NameG VarName) (mkPkgName "main")) (mkModName "Main"))) > else > error "value isn't fine") > • In the untyped splice: $($(checkGrammar_2 'thename_empty)) > > Thanks Michael! You’re a star! > > I should document this in a gist or blog post or something as a technique > for DSL checking. > > On Thu, 22 Aug 2019 at 16:26, Christopher Done > wrote: > >> I considered an expression-within-an-expression but thought a >> stage-restriction would break it. Maybe not! Let me go test it! >> >> On Wed, 21 Aug 2019 at 17:31, Michael Sloan wrote: >> >>> One potential solution here is to have checkGrammar_take2 return an >>> expression which returns an expression. I haven't tried compiling >>> this, but something roughly like: >>> >>> checkGrammar_2 name = [| if valueFine $(varE name) then varE name else >>> error "value isn't fine" |] >>> >>> Then it'd be used like $($(checkGrammar_2 'thename)). The th-orphans >>> package can also be useful for this because it provides Lift instances >>> for the TH AST. >>> >>> -Michael >>> >>> On Tue, Aug 20, 2019 at 10:36 AM Christopher Done >>> wrote: >>> > >>> > Hi all, >>> > >>> > Do we have already a syntax for ‘foo that also contains the typed >>> value like TExp? >>> > >>> > I have e.g. an AST that I want to do more static checks on it that >>> aren’t as convenient to do in the type system. Here’s an example: >>> > >>> > -- | Check the grammar spec to produce a grammar. >>> > checkGrammar :: (SchemaName, [(SchemaName, Schema)]) -> Q Exp >>> > checkGrammar (toplevel, rules) = >>> > if M.size rulesMap /= length rules >>> > then error "Duplicate rule names in grammar." >>> > else lift (Grammar {grammarToplevel = toplevel, grammarRules = >>> rulesMap}) >>> > where >>> > rulesMap = M.fromList rules >>> > >>> > -- | Grammar for Haskell. >>> > grammar :: Grammar >>> > grammar = $(checkGrammar $ runDefine $ mdo >>> > -- General expression >>> > expression <- rule "Expression" (ChoiceSchema [variable, >>> constructor, parentheses >>> > ,tuple, let', >>> application, string]) >>> > application <- rule "Application" (CompositeSchema [expression, >>> expression]) >>> > parentheses <- rule "Parentheses" (CompositeSchema >>> [openParenSchema, expression, closeParenSchema]) >>> > >>> > ... >>> > pure expression) >>> > >>> > Here I do a trivial check for duplicates. After I’ve checked the >>> > expression at compile-time, I Lift it so that it can be used at >>> > runtime. That’s pretty good. But some types like (a -> b) don’t Lift. >>> So >>> > an alternative would be: >>> > >>> > grammar = $(checkGrammar_take2 thename 'thename) >>> > >>> > In which checkGrammar_take2 would: >>> > >>> > Use thename at compile-time for a check. >>> > If the check passes, then return (VarE thename) >>> > >>> > E.g. >>> > >>> > checkGrammar_take2 value name = if valueFine value then varE name else >>> > error "value isn't fine" >>> > >>> > That’s actually quite a good solution because it avoids a lift, and I >>> > didn’t transform the AST. It’s also more efficient than lifting. >>> > >>> > But there’s no checked relationship between thename and ‘thename. >>> > checkGrammar_take2 has no way of knowing that they refer to the same >>> > thing. See? >>> > >>> > Hence, if I could get e.g. `thename to produce both the value and a >>> > name for the value, that would be cool. My gist doesn’t go this >>> > far. It might look like this: >>> > >>> > checkGrammar_take2 namedValue = if valueFine (getValue namedValue) >>> then getExp namedValue else error "value isn't fine" >>> > >>> > and call it like: >>> > >>> > mygrammar = checkGrammar_take2 `thename >>> > >>> > So the semantics would be roughly similar to >>> > >>> > [|| thename ||] :: TExp a >>> > >>> > but you’d get >>> > >>> > `thename :: Named a >>> > >>> > where >>> > >>> > data Named a = { namedThing :: a, nameOfThing :: Name } >>> > >>> > I feel like the more DSLs I design, the more I’d like something like >>> this to perform my static checks. >>> > >>> > Cheers, >>> > >>> > Chris >>> > >>> > _______________________________________________ >>> > Haskell-Cafe mailing list >>> > To (un)subscribe, modify options or view archives go to: >>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >>> > Only members subscribed via the mailman list are allowed to post. >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From chrisdone at gmail.com Thu Aug 22 16:49:37 2019 From: chrisdone at gmail.com (Christopher Done) Date: Thu, 22 Aug 2019 17:49:37 +0100 Subject: [Haskell-cafe] Getting both the value and name of a variable in one expression In-Reply-To: References: Message-ID: Wrote up here! https://chrisdone.com/posts/static-smart-constructors/ This was totally blocking my library from becoming complete, I'm super happy I can proceed now. On Thu, 22 Aug 2019 at 17:09, Christopher Done wrote: > Depending on how much syntactic overhead you’re happy with, you can go > full type-safe: > > checkGrammar_3 :: Q (TExp String) -> Q (TExp (Q (TExp String)))checkGrammar_3 q = do > TExp expr <- q > [|| if valueFine $$(q) > then pure (TExp expr) > else error "value is not fine" ||] > > > $$($$(checkGrammar_3 [|| thename ||]))"Hello!" > > $$($$(checkGrammar_3 [|| thename_empty ||])) > > :45:4: error: > • Exception when trying to run compile-time code: > value is not fine > > In my case it might even be a fine trade-off, because I’m favoring > TH-based validation of a DSL where doing it with e.g. type-level lists and > type families has worse type-inference and a higher price to pay in > type-signatures. So I can make a “static-smart” constructor that looks more > like: > > checkGrammar_3 :: Q (TExp (Tree a)) -> Q (TExp (Q (TExp (ValidTree a))))useValidTree :: ValidTree a -> ... > > So you pay the cost once here, but when building the tree, which is more > larger code, you don’t pay any cost, and there’s where it matters. > > On Thu, 22 Aug 2019 at 16:40, Christopher Done > wrote: > >> Hurray! It works! >> >> {-# LANGUAGE TemplateHaskell #-}import Language.Haskell.TH.Syntaximport Language.Haskell.THimport Language.Haskell.TH.Lift () >> valueFine :: String -> BoolvalueFine = not . null >> checkGrammar_2 :: Name -> ExpQcheckGrammar_2 name = >> [| if valueFine $(varE name) >> then varE name >> else error "value isn't fine" |] >> thename :: [Char]thename = "Hello!" >> thename_empty :: [Char]thename_empty = "" >> >> The output: >> >> > :t $(checkGrammar_2 'thename) >> $(checkGrammar_2 'thename) :: ExpQ >> > :t $($(checkGrammar_2 'thename)) >> $($(checkGrammar_2 'thename)) :: [Char] >> > $($(checkGrammar_2 'thename))"Hello!" >> > $($(checkGrammar_2 'thename_empty)) >> >> :49:1: error: >> • Exception when trying to run compile-time code: >> value isn't fineCallStack (from HasCallStack): >> error, called at :49:5 in interactive:Ghci2 >> Code: (if valueFine thename_empty then >> varE >> ((Name (mkOccName "thename_empty")) >> (((NameG VarName) (mkPkgName "main")) (mkModName "Main"))) >> else >> error "value isn't fine") >> • In the untyped splice: $($(checkGrammar_2 'thename_empty)) >> >> Thanks Michael! You’re a star! >> >> I should document this in a gist or blog post or something as a technique >> for DSL checking. >> >> On Thu, 22 Aug 2019 at 16:26, Christopher Done >> wrote: >> >>> I considered an expression-within-an-expression but thought a >>> stage-restriction would break it. Maybe not! Let me go test it! >>> >>> On Wed, 21 Aug 2019 at 17:31, Michael Sloan wrote: >>> >>>> One potential solution here is to have checkGrammar_take2 return an >>>> expression which returns an expression. I haven't tried compiling >>>> this, but something roughly like: >>>> >>>> checkGrammar_2 name = [| if valueFine $(varE name) then varE name else >>>> error "value isn't fine" |] >>>> >>>> Then it'd be used like $($(checkGrammar_2 'thename)). The th-orphans >>>> package can also be useful for this because it provides Lift instances >>>> for the TH AST. >>>> >>>> -Michael >>>> >>>> On Tue, Aug 20, 2019 at 10:36 AM Christopher Done >>>> wrote: >>>> > >>>> > Hi all, >>>> > >>>> > Do we have already a syntax for ‘foo that also contains the typed >>>> value like TExp? >>>> > >>>> > I have e.g. an AST that I want to do more static checks on it that >>>> aren’t as convenient to do in the type system. Here’s an example: >>>> > >>>> > -- | Check the grammar spec to produce a grammar. >>>> > checkGrammar :: (SchemaName, [(SchemaName, Schema)]) -> Q Exp >>>> > checkGrammar (toplevel, rules) = >>>> > if M.size rulesMap /= length rules >>>> > then error "Duplicate rule names in grammar." >>>> > else lift (Grammar {grammarToplevel = toplevel, grammarRules = >>>> rulesMap}) >>>> > where >>>> > rulesMap = M.fromList rules >>>> > >>>> > -- | Grammar for Haskell. >>>> > grammar :: Grammar >>>> > grammar = $(checkGrammar $ runDefine $ mdo >>>> > -- General expression >>>> > expression <- rule "Expression" (ChoiceSchema [variable, >>>> constructor, parentheses >>>> > ,tuple, let', >>>> application, string]) >>>> > application <- rule "Application" (CompositeSchema >>>> [expression, expression]) >>>> > parentheses <- rule "Parentheses" (CompositeSchema >>>> [openParenSchema, expression, closeParenSchema]) >>>> > >>>> > ... >>>> > pure expression) >>>> > >>>> > Here I do a trivial check for duplicates. After I’ve checked the >>>> > expression at compile-time, I Lift it so that it can be used at >>>> > runtime. That’s pretty good. But some types like (a -> b) don’t Lift. >>>> So >>>> > an alternative would be: >>>> > >>>> > grammar = $(checkGrammar_take2 thename 'thename) >>>> > >>>> > In which checkGrammar_take2 would: >>>> > >>>> > Use thename at compile-time for a check. >>>> > If the check passes, then return (VarE thename) >>>> > >>>> > E.g. >>>> > >>>> > checkGrammar_take2 value name = if valueFine value then varE name else >>>> > error "value isn't fine" >>>> > >>>> > That’s actually quite a good solution because it avoids a lift, and I >>>> > didn’t transform the AST. It’s also more efficient than lifting. >>>> > >>>> > But there’s no checked relationship between thename and ‘thename. >>>> > checkGrammar_take2 has no way of knowing that they refer to the same >>>> > thing. See? >>>> > >>>> > Hence, if I could get e.g. `thename to produce both the value and a >>>> > name for the value, that would be cool. My gist doesn’t go this >>>> > far. It might look like this: >>>> > >>>> > checkGrammar_take2 namedValue = if valueFine (getValue namedValue) >>>> then getExp namedValue else error "value isn't fine" >>>> > >>>> > and call it like: >>>> > >>>> > mygrammar = checkGrammar_take2 `thename >>>> > >>>> > So the semantics would be roughly similar to >>>> > >>>> > [|| thename ||] :: TExp a >>>> > >>>> > but you’d get >>>> > >>>> > `thename :: Named a >>>> > >>>> > where >>>> > >>>> > data Named a = { namedThing :: a, nameOfThing :: Name } >>>> > >>>> > I feel like the more DSLs I design, the more I’d like something like >>>> this to perform my static checks. >>>> > >>>> > Cheers, >>>> > >>>> > Chris >>>> > >>>> > _______________________________________________ >>>> > Haskell-Cafe mailing list >>>> > To (un)subscribe, modify options or view archives go to: >>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >>>> > Only members subscribed via the mailman list are allowed to post. >>>> >>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Thu Aug 22 17:10:43 2019 From: mgsloan at gmail.com (Michael Sloan) Date: Thu, 22 Aug 2019 11:10:43 -0600 Subject: [Haskell-cafe] Getting both the value and name of a variable in one expression In-Reply-To: References: Message-ID: Awesome Chris, glad the idea was applicable! Nice post on the topic, I hadn't thought of using this for more powerful validation of values. Use of quasiquotes and such for validated literals is well known, but this approach allows compiletime validation of the results of arbitrary expressions and not just strings! Very cool. On Thu, Aug 22, 2019 at 10:49 AM Christopher Done wrote: > Wrote up here! https://chrisdone.com/posts/static-smart-constructors/ > > This was totally blocking my library from becoming complete, I'm super > happy I can proceed now. > > On Thu, 22 Aug 2019 at 17:09, Christopher Done > wrote: > >> Depending on how much syntactic overhead you’re happy with, you can go >> full type-safe: >> >> checkGrammar_3 :: Q (TExp String) -> Q (TExp (Q (TExp String)))checkGrammar_3 q = do >> TExp expr <- q >> [|| if valueFine $$(q) >> then pure (TExp expr) >> else error "value is not fine" ||] >> >> > $$($$(checkGrammar_3 [|| thename ||]))"Hello!" >> > $$($$(checkGrammar_3 [|| thename_empty ||])) >> >> :45:4: error: >> • Exception when trying to run compile-time code: >> value is not fine >> >> In my case it might even be a fine trade-off, because I’m favoring >> TH-based validation of a DSL where doing it with e.g. type-level lists and >> type families has worse type-inference and a higher price to pay in >> type-signatures. So I can make a “static-smart” constructor that looks more >> like: >> >> checkGrammar_3 :: Q (TExp (Tree a)) -> Q (TExp (Q (TExp (ValidTree a))))useValidTree :: ValidTree a -> ... >> >> So you pay the cost once here, but when building the tree, which is more >> larger code, you don’t pay any cost, and there’s where it matters. >> >> On Thu, 22 Aug 2019 at 16:40, Christopher Done >> wrote: >> >>> Hurray! It works! >>> >>> {-# LANGUAGE TemplateHaskell #-}import Language.Haskell.TH.Syntaximport Language.Haskell.THimport Language.Haskell.TH.Lift () >>> valueFine :: String -> BoolvalueFine = not . null >>> checkGrammar_2 :: Name -> ExpQcheckGrammar_2 name = >>> [| if valueFine $(varE name) >>> then varE name >>> else error "value isn't fine" |] >>> thename :: [Char]thename = "Hello!" >>> thename_empty :: [Char]thename_empty = "" >>> >>> The output: >>> >>> > :t $(checkGrammar_2 'thename) >>> $(checkGrammar_2 'thename) :: ExpQ >>> > :t $($(checkGrammar_2 'thename)) >>> $($(checkGrammar_2 'thename)) :: [Char] >>> > $($(checkGrammar_2 'thename))"Hello!" >>> > $($(checkGrammar_2 'thename_empty)) >>> >>> :49:1: error: >>> • Exception when trying to run compile-time code: >>> value isn't fineCallStack (from HasCallStack): >>> error, called at :49:5 in interactive:Ghci2 >>> Code: (if valueFine thename_empty then >>> varE >>> ((Name (mkOccName "thename_empty")) >>> (((NameG VarName) (mkPkgName "main")) (mkModName "Main"))) >>> else >>> error "value isn't fine") >>> • In the untyped splice: $($(checkGrammar_2 'thename_empty)) >>> >>> Thanks Michael! You’re a star! >>> >>> I should document this in a gist or blog post or something as a >>> technique for DSL checking. >>> >>> On Thu, 22 Aug 2019 at 16:26, Christopher Done >>> wrote: >>> >>>> I considered an expression-within-an-expression but thought a >>>> stage-restriction would break it. Maybe not! Let me go test it! >>>> >>>> On Wed, 21 Aug 2019 at 17:31, Michael Sloan wrote: >>>> >>>>> One potential solution here is to have checkGrammar_take2 return an >>>>> expression which returns an expression. I haven't tried compiling >>>>> this, but something roughly like: >>>>> >>>>> checkGrammar_2 name = [| if valueFine $(varE name) then varE name else >>>>> error "value isn't fine" |] >>>>> >>>>> Then it'd be used like $($(checkGrammar_2 'thename)). The th-orphans >>>>> package can also be useful for this because it provides Lift instances >>>>> for the TH AST. >>>>> >>>>> -Michael >>>>> >>>>> On Tue, Aug 20, 2019 at 10:36 AM Christopher Done >>>>> wrote: >>>>> > >>>>> > Hi all, >>>>> > >>>>> > Do we have already a syntax for ‘foo that also contains the typed >>>>> value like TExp? >>>>> > >>>>> > I have e.g. an AST that I want to do more static checks on it that >>>>> aren’t as convenient to do in the type system. Here’s an example: >>>>> > >>>>> > -- | Check the grammar spec to produce a grammar. >>>>> > checkGrammar :: (SchemaName, [(SchemaName, Schema)]) -> Q Exp >>>>> > checkGrammar (toplevel, rules) = >>>>> > if M.size rulesMap /= length rules >>>>> > then error "Duplicate rule names in grammar." >>>>> > else lift (Grammar {grammarToplevel = toplevel, grammarRules = >>>>> rulesMap}) >>>>> > where >>>>> > rulesMap = M.fromList rules >>>>> > >>>>> > -- | Grammar for Haskell. >>>>> > grammar :: Grammar >>>>> > grammar = $(checkGrammar $ runDefine $ mdo >>>>> > -- General expression >>>>> > expression <- rule "Expression" (ChoiceSchema [variable, >>>>> constructor, parentheses >>>>> > ,tuple, let', >>>>> application, string]) >>>>> > application <- rule "Application" (CompositeSchema >>>>> [expression, expression]) >>>>> > parentheses <- rule "Parentheses" (CompositeSchema >>>>> [openParenSchema, expression, closeParenSchema]) >>>>> > >>>>> > ... >>>>> > pure expression) >>>>> > >>>>> > Here I do a trivial check for duplicates. After I’ve checked the >>>>> > expression at compile-time, I Lift it so that it can be used at >>>>> > runtime. That’s pretty good. But some types like (a -> b) don’t >>>>> Lift. So >>>>> > an alternative would be: >>>>> > >>>>> > grammar = $(checkGrammar_take2 thename 'thename) >>>>> > >>>>> > In which checkGrammar_take2 would: >>>>> > >>>>> > Use thename at compile-time for a check. >>>>> > If the check passes, then return (VarE thename) >>>>> > >>>>> > E.g. >>>>> > >>>>> > checkGrammar_take2 value name = if valueFine value then varE name >>>>> else >>>>> > error "value isn't fine" >>>>> > >>>>> > That’s actually quite a good solution because it avoids a lift, and I >>>>> > didn’t transform the AST. It’s also more efficient than lifting. >>>>> > >>>>> > But there’s no checked relationship between thename and ‘thename. >>>>> > checkGrammar_take2 has no way of knowing that they refer to the same >>>>> > thing. See? >>>>> > >>>>> > Hence, if I could get e.g. `thename to produce both the value and a >>>>> > name for the value, that would be cool. My gist doesn’t go this >>>>> > far. It might look like this: >>>>> > >>>>> > checkGrammar_take2 namedValue = if valueFine (getValue namedValue) >>>>> then getExp namedValue else error "value isn't fine" >>>>> > >>>>> > and call it like: >>>>> > >>>>> > mygrammar = checkGrammar_take2 `thename >>>>> > >>>>> > So the semantics would be roughly similar to >>>>> > >>>>> > [|| thename ||] :: TExp a >>>>> > >>>>> > but you’d get >>>>> > >>>>> > `thename :: Named a >>>>> > >>>>> > where >>>>> > >>>>> > data Named a = { namedThing :: a, nameOfThing :: Name } >>>>> > >>>>> > I feel like the more DSLs I design, the more I’d like something like >>>>> this to perform my static checks. >>>>> > >>>>> > Cheers, >>>>> > >>>>> > Chris >>>>> > >>>>> > _______________________________________________ >>>>> > Haskell-Cafe mailing list >>>>> > To (un)subscribe, modify options or view archives go to: >>>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >>>>> > Only members subscribed via the mailman list are allowed to post. >>>>> >>>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From andrew.lelechenko at gmail.com Fri Aug 23 20:43:32 2019 From: andrew.lelechenko at gmail.com (Andrew Lelechenko) Date: Fri, 23 Aug 2019 21:43:32 +0100 Subject: [Haskell-cafe] ANN bitvec-1.0.0.1 Message-ID: <0C5FA4B6-D7B1-46AE-BC39-839F914AF80B@gmail.com> Hello, I am happy to announce the stable release of bitvec-1.0.0.1. This package provides a "better" Vector instance for Bool. An unboxed Vector Bool spends 8 bits per boolean, while bitvec provides a newtype Bit and a custom instance of Vector, packing booleans densely and achieving 8x less memory footprint. Performance stays roughly the same, and certain bulk operations become up to 64x faster. http://hackage.haskell.org/package/bitvec-1.0.0.1 https://github.com/Bodigrim/bitvec#readme Best regards, Andrew From simon.jakobi at googlemail.com Fri Aug 23 21:40:02 2019 From: simon.jakobi at googlemail.com (Simon Jakobi) Date: Fri, 23 Aug 2019 23:40:02 +0200 Subject: [Haskell-cafe] ANN bitvec-1.0.0.1 In-Reply-To: <0C5FA4B6-D7B1-46AE-BC39-839F914AF80B@gmail.com> References: <0C5FA4B6-D7B1-46AE-BC39-839F914AF80B@gmail.com> Message-ID: Thanks Andrew, that looks like a well-crafted package! Thumbs up for the docs! :) Cheers, Simon Am Fr., 23. Aug. 2019 um 22:44 Uhr schrieb Andrew Lelechenko < andrew.lelechenko at gmail.com>: > Hello, > > I am happy to announce the stable release of bitvec-1.0.0.1. This package > provides a "better" Vector instance for Bool. > > An unboxed Vector Bool spends 8 bits per boolean, while bitvec provides a > newtype Bit and a custom instance of Vector, packing booleans densely and > achieving 8x less memory footprint. Performance stays roughly the same, and > certain bulk operations become up to 64x faster. > > http://hackage.haskell.org/package/bitvec-1.0.0.1 > https://github.com/Bodigrim/bitvec#readme > > Best regards, > Andrew > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ben at well-typed.com Mon Aug 26 09:25:12 2019 From: ben at well-typed.com (Ben Gamari) Date: Mon, 26 Aug 2019 05:25:12 -0400 Subject: [Haskell-cafe] [ANNOUNCE] GHC 8.8.1 is now available Message-ID: <87zhjwl1mx.fsf@smart-cactus.org> Hello everyone, The GHC team is pleased to announce the release candidate for GHC 8.8.1. The source distribution, binary distributions, and documentation are available at https://downloads.haskell.org/ghc/8.8.1 This release is the culmination of over 3000 commits by over one hundred contributors and has several new features and numerous bug fixes relative to GHC 8.6: * Visible kind applications are now supported (GHC Proposal #15) * Profiling now works correctly on 64-bit Windows (although still may be problematic on 32-bit Windows due to platform limitations; see #15934) * A new code layout algorithm for amd64's native code generator significantly improving the runtime performance of some kernels * The introduction of a late lambda-lifting pass which may reduce allocations significantly for some programs. * Further work on Trees That Grow, enabling improved code re-use of the Haskell AST in tooling * Users can write `forall` in more contexts (GHC Proposal #7) * The pattern-match checker is now more precise in the presence of strict fields with uninhabited types. * A comprehensive audit of GHC's memory ordering barriers has been performed, resulting in a number of fixes that should significantly improve the reliability of programs on architectures with weakly-ordered memory models (e.g. PowerPC, many ARM and AArch64 implementations). * A long-standing linker limitation rendering GHCi unusable with projects with cyclic symbol dependencies has been fixed (#13786) * Further work on the Hadrian build system * Countless miscellaneous bug-fixes Unfortunately, due to a build issue (#17108) found late in the release process i386 Windows builds are currently unavailable. These will be provided in the coming weeks. As always, if anything looks amiss do let us know. Happy compiling! Cheers, - Ben [1] https://downloads.haskell.org/ghc/8.8.1/docs/html/users_guide/8.8.1-notes.html -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 487 bytes Desc: not available URL: From publicityifl at gmail.com Mon Aug 26 14:28:31 2019 From: publicityifl at gmail.com (Jurriaan Hage) Date: Mon, 26 Aug 2019 07:28:31 -0700 Subject: [Haskell-cafe] First call for participation for IFL 2019 (Implementation and Application of Functional Languages) Message-ID: Hello, Please, find below the first call for participation for IFL 2019. Please forward these to anyone you think may be interested. Apologies for any duplicates you may receive. best regards, Jurriaan Hage Publicity Chair of IFL ================================================================================ IFL 2019 31st Symposium on Implementation and Application of Functional Languages National University of Singapore September 25th-27th, 2019 http://2019.iflconference.org ================================================================================ ### Scope The goal of the IFL symposia is to bring together researchers actively engaged in the implementation and application of functional and function-based programming languages. IFL 2019 will be a venue for researchers to present and discuss new ideas and concepts, work in progress, and publication-ripe results related to the implementation and application of functional languages and function-based programming. Topics of interest to IFL include, but are not limited to: - language concepts - type systems, type checking, type inferencing - compilation techniques - staged compilation - run-time function specialization - run-time code generation - partial evaluation - (abstract) interpretation - metaprogramming - generic programming - automatic program generation - array processing - concurrent/parallel programming - concurrent/parallel program execution - embedded systems - web applications - (embedded) domain specific languages - security - novel memory management techniques - run-time profiling performance measurements - debugging and tracing - virtual/abstract machine architectures - validation, verification of functional programs - tools and programming techniques - (industrial) applications ### Keynote Speaker * Olivier Danvy, Yale-NUS College ### Submissions and peer-review Differently from previous editions of IFL, IFL 2019 solicits two kinds of submissions: * Regular papers (12 pages including references) * Draft papers for presentations ('weak' limit between 8 and 15 pages) Regular papers will undergo a rigorous review by the program committee, and will be evaluated according to their correctness, novelty, originality, relevance, significance, and clarity. A set of regular papers will be conditionally accepted for publication. Authors of conditionally accepted papers will be provided with committee reviews along with a set of mandatory revisions. Regular papers not accepted for publication will be considered as draft papers, at the request of the author. Draft papers will be screened to make sure that they are within the scope of IFL, and will be accepted for presentation or rejected accordingly. Prior to the symposium: Authors of conditionally accepted papers and accepted presentations will submit a pre-proceedings version of their work that will appear in the draft proceedings distributed at the symposium. The draft proceedings does not constitute a formal publication. We require that at least one of the authors present the work at IFL 2019. After the symposium: Authors of conditionally accepted papers will submit a revised versions of their paper for the formal post-proceedings. The program committee will assess whether the mandatory revisions have been adequately addressed by the authors and thereby determines the final accept/reject status of the paper. Our interest is to ultimately accept all conditionally accepted papers. If you are an author of a conditionally accepted paper, please make sure that you address all the concerns of the reviewers. Authors of accepted presentations will be given the opportunity to incorporate the feedback from discussions at the symposium and will be invited to submit a revised full article for the formal post-proceedings. The program committee will evaluate these submissions according to their correctness, novelty, originality, relevance, significance, and clarity, and will thereby determine whether the paper is accepted or rejected. ### Publication The formal proceedings will appear in the International Conference Proceedings Series of the ACM Digital Library. At no time may work submitted to IFL be simultaneously submitted to other venues; submissions must adhere to ACM SIGPLAN's republication policy: http://www.sigplan.org/Resources/Policies/Republication ### Important dates Submission of regular papers: June 15, 2019 Submission of draft papers: August 1, 2019 Regular papers notification: August 1, 2019 Regular draft papers notification: August 7, 2019 Deadline for early registration: August 31, 2019 Submission of pre-proceedings version: September 15, 2019 IFL Symposium: September 25-27, 2019 Submission of papers for post-proceedings: November 30, 2019 Notification of acceptance: January 31, 2020 Camera-ready version: February 29, 2020 ### Submission details All contributions must be written in English. Papers must use the ACM two columns conference format, which can be found at: http://www.acm.org/publications/proceedings-template Authors submit through EasyChair: https://easychair.org/conferences/?conf=ifl2019 ### Peter Landin Prize The Peter Landin Prize is awarded to the best paper presented at the symposium every year. The honored article is selected by the program committee based on the submissions received for the formal review process. The prize carries a cash award equivalent to 150 Euros. ### Organization and Program committee Chairs: Jurrien Stutterheim (Standard Chartered Bank Singapore), Wei Ngan Chin (National University of Singapore) Program Committee: - Olaf Chitil, University of Kent - Clemens Grelck, University of Amsterdam - Daisuke Kimura, Toho University - Pieter Koopman, Radboud University - Tamás Kozsik, Eötvös Loránd University - Roman Leschinskiy, Facebook - Ben Lippmeier, The University of New South Wales - Marco T. Morazan, Seton Hall University - Sven-Bodo Scholz, Heriot-Watt University - Tom Schrijvers, Katholieke Universiteit Leuven - Alejandro Serrano, Utrecht University - Tony Sloane, Macquarie University - Simon Thompson, University of Kent - Marcos Viera, Universidad de la República - Wei Ngan Chin, NUS - Jurriën Stutterheim, Standard Chartered Bank ### Venue The 31st IFL is organized by the National University of Singapore. Singapore is located in the heart of South-East Asia, and the city itself is extremely well connected by trains and taxis. See the website for more information on the venue. ### Acknowledgments This call-for-papers is an adaptation and evolution of content from previous instances of IFL. We are grateful to prior organizers for their work, which is reused here. A part of IFL 2019 format and CFP language that describes conditionally accepted papers has been adapted from call-for-papers of OOPSLA conferences. -------------- next part -------------- An HTML attachment was scrubbed... URL: From evan at evan-borden.com Mon Aug 26 15:17:33 2019 From: evan at evan-borden.com (Evan Borden) Date: Mon, 26 Aug 2019 10:17:33 -0500 Subject: [Haskell-cafe] ANN: bcp47 Message-ID: Announcing bcp47, http://hackage.haskell.org/package/bcp47-0.1.0.0 This library provides language tags as specified by https://tools.ietf.org/html/bcp47 As well it provides a trie like data structure for collecting and querying data that varies by language. -------------- next part -------------- An HTML attachment was scrubbed... URL: From leah at vuxu.org Tue Aug 27 11:20:46 2019 From: leah at vuxu.org (Leah Neukirchen) Date: Tue, 27 Aug 2019 13:20:46 +0200 Subject: [Haskell-cafe] Munich Haskell Meeting, 2019-08-29 @ 19:30 Message-ID: <8736hmhn1t.fsf@vuxu.org> Dear all, This week, our monthly Munich Haskell Meeting will take place again on Thursday, August 29 at Augustiner-Gaststätte Rumpler at 19h30. For details see here: http://muenchen.haskell.bayern/dates.html If you plan to join, please add yourself to this dudle so we can reserve enough seats! It is OK to add yourself to the dudle anonymously or pseudonymously. https://dudle.inf.tu-dresden.de/haskell-munich-aug-2019/ Everybody is welcome! cu, -- Leah Neukirchen https://leahneukirchen.org/ From klebinger.andreas at gmx.at Tue Aug 27 16:10:30 2019 From: klebinger.andreas at gmx.at (Andreas Klebinger) Date: Tue, 27 Aug 2019 18:10:30 +0200 Subject: [Haskell-cafe] GHC: Policy on -O flags? Message-ID: Hello ghc-devs and haskell users. I'm looking for opinions on when an optimization should be enabled by default. -O is currently the base line for an optimized build. -O2 adds around 10-20% compile time for a few % (around 2% if I remember correctly) in performance for most things. The question is now if I implement a new optimization, making code R% faster but slowing down the compiler down by C% at which point should an optimization be: * Enabled by default (-O) * Enabled only at -O2 * Disabled by default Cheap always beneficial things make sense for -O Expensive optimizations which add little make sense for -O2 But where exactly is the line here? How much compile time is runtime worth? If something slows down the compiler by 1%/2%/5% and speeds up code by 0.5%/1%/2% which combinations make sense for -O, -O2? Can there even be a good policy with the -O/-O2 split? Personally I generally want code to either: * Typecheck/Run at all (-O0, -fno-code, repl) * Not blow through all my RAM when adding a few Ints while developing: -O ? * Make a reasonable tradeoff between runtime/compiletime: -O ? * Give me all you got: -O2 (-O99999) The use case for -O0 is rather clear, so is -O2. But what do people consider the use case for -O What trade offs seem acceptable to you as a user of GHC? Is it ok for -O to become slower for faster runtimes? How much slower? Should all new improvements which might slow down compilation be pushed to -O2? Or does an ideal solution add new flags? Tell me what do you think. Cheers, Andreas Klebinger From allbery.b at gmail.com Tue Aug 27 16:12:47 2019 From: allbery.b at gmail.com (Brandon Allbery) Date: Tue, 27 Aug 2019 12:12:47 -0400 Subject: [Haskell-cafe] GHC: Policy on -O flags? In-Reply-To: References: Message-ID: I think at first you just give it a -f flag, and let experience determine whether it should be part of -O or -O2. On Tue, Aug 27, 2019 at 12:10 PM Andreas Klebinger wrote: > Hello ghc-devs and haskell users. > > I'm looking for opinions on when an optimization should be enabled by > default. > > -O is currently the base line for an optimized build. > -O2 adds around 10-20% compile time for a few % (around 2% if I remember > correctly) in performance for most things. > > The question is now if I implement a new optimization, making code R% > faster but slowing > down the compiler down by C% at which point should an optimization be: > > * Enabled by default (-O) > * Enabled only at -O2 > * Disabled by default > > Cheap always beneficial things make sense for -O > Expensive optimizations which add little make sense for -O2 > > But where exactly is the line here? > How much compile time is runtime worth? > > If something slows down the compiler by 1%/2%/5% > and speeds up code by 0.5%/1%/2% which combinations make sense > for -O, -O2? > > Can there even be a good policy with the -O/-O2 split? > > Personally I generally want code to either: > * Typecheck/Run at all (-O0, -fno-code, repl) > * Not blow through all my RAM when adding a few Ints while developing: -O ? > * Make a reasonable tradeoff between runtime/compiletime: -O ? > * Give me all you got: -O2 (-O99999) > > The use case for -O0 is rather clear, so is -O2. > But what do people consider the use case for -O > > What trade offs seem acceptable to you as a user of GHC? > > Is it ok for -O to become slower for faster runtimes? How much slower? > Should all new improvements which might slow down compilation > be pushed to -O2? > > Or does an ideal solution add new flags? > Tell me what do you think. > > Cheers, > Andreas Klebinger > > _______________________________________________ > ghc-devs mailing list > ghc-devs at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs > -- brandon s allbery kf8nh allbery.b at gmail.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From matthewtpickering at gmail.com Tue Aug 27 16:17:38 2019 From: matthewtpickering at gmail.com (Matthew Pickering) Date: Tue, 27 Aug 2019 17:17:38 +0100 Subject: [Haskell-cafe] GHC: Policy on -O flags? In-Reply-To: References: Message-ID: `-O2` is not a very rationally considered flag from what I understand. It only enables `-fspec-constr` and `-fliberate-case`. The later also triggers another simplification pass. `-fspec-constr` is quite limited as it only works in the definition module. I have never trusted it to optimise my code. I have seen `-fliberate-case` achieve something but more often the improvement comes from the extra simplification pass. Therefore I wouldn't try to read the tea leaves too closely. There are probably flags in `-O` which affect compile time more but have less benefit. Matt On Tue, Aug 27, 2019 at 5:13 PM Brandon Allbery wrote: > > I think at first you just give it a -f flag, and let experience determine whether it should be part of -O or -O2. > > On Tue, Aug 27, 2019 at 12:10 PM Andreas Klebinger wrote: >> >> Hello ghc-devs and haskell users. >> >> I'm looking for opinions on when an optimization should be enabled by >> default. >> >> -O is currently the base line for an optimized build. >> -O2 adds around 10-20% compile time for a few % (around 2% if I remember >> correctly) in performance for most things. >> >> The question is now if I implement a new optimization, making code R% >> faster but slowing >> down the compiler down by C% at which point should an optimization be: >> >> * Enabled by default (-O) >> * Enabled only at -O2 >> * Disabled by default >> >> Cheap always beneficial things make sense for -O >> Expensive optimizations which add little make sense for -O2 >> >> But where exactly is the line here? >> How much compile time is runtime worth? >> >> If something slows down the compiler by 1%/2%/5% >> and speeds up code by 0.5%/1%/2% which combinations make sense >> for -O, -O2? >> >> Can there even be a good policy with the -O/-O2 split? >> >> Personally I generally want code to either: >> * Typecheck/Run at all (-O0, -fno-code, repl) >> * Not blow through all my RAM when adding a few Ints while developing: -O ? >> * Make a reasonable tradeoff between runtime/compiletime: -O ? >> * Give me all you got: -O2 (-O99999) >> >> The use case for -O0 is rather clear, so is -O2. >> But what do people consider the use case for -O >> >> What trade offs seem acceptable to you as a user of GHC? >> >> Is it ok for -O to become slower for faster runtimes? How much slower? >> Should all new improvements which might slow down compilation >> be pushed to -O2? >> >> Or does an ideal solution add new flags? >> Tell me what do you think. >> >> Cheers, >> Andreas Klebinger >> >> _______________________________________________ >> ghc-devs mailing list >> ghc-devs at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs > > > > -- > brandon s allbery kf8nh > allbery.b at gmail.com > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. From sgraf1337 at gmail.com Tue Aug 27 16:21:45 2019 From: sgraf1337 at gmail.com (Sebastian Graf) Date: Tue, 27 Aug 2019 17:21:45 +0100 Subject: [Haskell-cafe] GHC: Policy on -O flags? In-Reply-To: References: Message-ID: Hi, I used to think that the policy for being eligible for -O1 is that C must be non-positive, e.g. that the compile times don't suffer at all. Everything beyond that (well, given that R is positive) should be -O2 only. There's precedent at least for Late Lambda Lifting (which is only run for -O2) here: https://phabricator.haskell.org/D5224#147959. Upon re-reading I see that Simon Marlow identified C=1 as the hard threshold. Maybe there are other cases as well? Personally, I like C=0 for the fact that it means the compiler will only get faster over time. And any reasonably tuned release executable will do -O2 anyway. Cheers, Sebastian Am Di., 27. Aug. 2019 um 17:11 Uhr schrieb Andreas Klebinger < klebinger.andreas at gmx.at>: > Hello ghc-devs and haskell users. > > I'm looking for opinions on when an optimization should be enabled by > default. > > -O is currently the base line for an optimized build. > -O2 adds around 10-20% compile time for a few % (around 2% if I remember > correctly) in performance for most things. > > The question is now if I implement a new optimization, making code R% > faster but slowing > down the compiler down by C% at which point should an optimization be: > > * Enabled by default (-O) > * Enabled only at -O2 > * Disabled by default > > Cheap always beneficial things make sense for -O > Expensive optimizations which add little make sense for -O2 > > But where exactly is the line here? > How much compile time is runtime worth? > > If something slows down the compiler by 1%/2%/5% > and speeds up code by 0.5%/1%/2% which combinations make sense > for -O, -O2? > > Can there even be a good policy with the -O/-O2 split? > > Personally I generally want code to either: > * Typecheck/Run at all (-O0, -fno-code, repl) > * Not blow through all my RAM when adding a few Ints while developing: -O ? > * Make a reasonable tradeoff between runtime/compiletime: -O ? > * Give me all you got: -O2 (-O99999) > > The use case for -O0 is rather clear, so is -O2. > But what do people consider the use case for -O > > What trade offs seem acceptable to you as a user of GHC? > > Is it ok for -O to become slower for faster runtimes? How much slower? > Should all new improvements which might slow down compilation > be pushed to -O2? > > Or does an ideal solution add new flags? > Tell me what do you think. > > Cheers, > Andreas Klebinger > > _______________________________________________ > ghc-devs mailing list > ghc-devs at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs > -------------- next part -------------- An HTML attachment was scrubbed... URL: From publicityifl at gmail.com Wed Aug 28 15:21:27 2019 From: publicityifl at gmail.com (Jurriaan Hage) Date: Wed, 28 Aug 2019 08:21:27 -0700 Subject: [Haskell-cafe] First call for draft papers for TFPIE 2020 (Trends in Functional Programming in Education) Message-ID: Hello, Please, find below the final call for draft papers for TFPIE 2020. Please forward these to anyone you think may be interested. Apologies for any duplicates you may receive. best regards, Jurriaan Hage Chair of TFPIE 2020 ======================================================================== TFPIE 2020 Call for papers http://www.staff.science.uu.nl/~hage0101/tfpie2020/index.html February 12th 2020, Krakow, Poland (co-located with TFP 2020 and Lambda Days) TFPIE 2020 welcomes submissions describing techniques used in the classroom, tools used in and/or developed for the classroom and any creative use of functional programming (FP) to aid education in or outside Computer Science. Topics of interest include, but are not limited to: FP and beginning CS students FP and Computational Thinking FP and Artificial Intelligence FP in Robotics FP and Music Advanced FP for undergraduates FP in graduate education Engaging students in research using FP FP in Programming Languages FP in the high school curriculum FP as a stepping stone to other CS topics FP and Philosophy The pedagogy of teaching FP FP and e-learning: MOOCs, automated assessment etc. Best Lectures - more details below In addition to papers, we are requesting best lecture presentations. What's your best lecture topic in an FP related course? Do you have a fun way to present FP concepts to novices or perhaps an especially interesting presentation of a difficult topic? In either case, please consider sharing it. Best lecture topics will be selected for presentation based on a short abstract describing the lecture and its interest to TFPIE attendees. The length of the presentation should be comparable to that of a paper. On top of the lecture itself, the presentation can also provide commentary on the lecture. Submissions Potential presenters are invited to submit an extended abstract (4-6 pages) or a draft paper (up to 20 pages) in EPTCS style. The authors of accepted presentations will have their preprints and their slides made available on the workshop's website. Papers and abstracts can be submitted via easychair at the following link: https://easychair.org/conferences/?conf=tfpie2020 . After the workshop, presenters will be invited to submit (a revised version of) their article for review. The PC will select the best articles that will be published in the Electronic Proceedings in Theoretical Computer Science (EPTCS). Articles rejected for presentation and extended abstracts will not be formally reviewed by the PC. Dates Submission deadline: January 14th 2020, Anywhere on Earth. Notification: January 17th 2020 TFPIE Registration Deadline: January 20th 2020 Workshop: February 12th 2020 Submission for formal review: April 19th 2020, Anywhere on Earth. Notification of full article: June 6th 2020 Camera ready: July 1st 2020 Program Committee Olaf Chitil - University of Kent Youyou Cong - Tokyo Institute of Technology Marko van Eekelen - Open University of the Netherlands and Radboud University Nijmegen Jurriaan Hage (Chair) - Utrecht University Marco T. Morazan - Seton Hall University, USA Sharon Tuttle - Humboldt State University, USA Janis Voigtlaender - University of Duisburg-Essen Viktoria Zsok - Eotvos Lorand University Note: information on TFP is available at http://www.cse.chalmers.se/~rjmh/tfp/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From manpacket at gmail.com Fri Aug 30 01:53:28 2019 From: manpacket at gmail.com (Mikhail Baykov) Date: Fri, 30 Aug 2019 09:53:28 +0800 Subject: [Haskell-cafe] Haskell internship at Tsuru Capital Message-ID: Hi Cafe It's that time of year again and we are looking for more interns. Haskell knowledge is required, experience with pricing futures/options would be nice but not necessary. Located in Tokyo, company language is English. Casual environment, nice monitors and a big coffee machine. Duration 3-6 months, starting at your convenience. We will help you with visa and looking for a place to stay. There's some salary. Details how to apply are on our website: http://www.tsurucapital.com/en/ Feel free to ask questions here, on Reddit or #tsurucapital on freenode. https://www.reddit.com/r/haskell/comments/cx8yei/tsuru_capital_is_looking_for_haskell_interns/ From david.feuer at gmail.com Fri Aug 30 02:11:43 2019 From: david.feuer at gmail.com (David Feuer) Date: Thu, 29 Aug 2019 22:11:43 -0400 Subject: [Haskell-cafe] A faithful strictly-accumulating writer Message-ID: It's widely known that the classic WriterT tends to leak space, and that in some cases this leak can be resolved by using StateT instead. The implementations I've seen of this idea both use the module system to prevent the computation from gaining unauthorized access to the state. I believe I've found a way to avoid this. Does this look right? {-# language RankNTypes, FlexibleInstances, MultiParamTypeClasses #-} import qualified Control.Monad.Writer.Class as W import Control.Monad.State.Strict import Control.Monad.Reader import Control.Applicative -- The key idea is that the computation -- can't inspect the state because it doesn't know the type newtype WriterT w m a = WriterT { unWriterT :: forall s. ReaderT ((w -> w) -> s -> s) (StateT s m) a } runWriterT :: Monoid w => WriterT w m a -> m (a, w) runWriterT m = runStateT (runReaderT (unWriterT m) id) mempty instance Functor m => Functor (WriterT w m) where fmap f m = WriterT $ fmap f (unWriterT m) instance Monad m => Applicative (WriterT w m) where pure a = WriterT (pure a) liftA2 f m n = WriterT $ liftA2 f (unWriterT m) (unWriterT n) instance Monad m => Monad (WriterT w m) where m >>= f = WriterT $ unWriterT m >>= unWriterT . f instance MonadTrans (WriterT w) where lift m = WriterT $ lift . lift $ m tell :: (Monad m, Semigroup w) => w -> WriterT w m () tell w = WriterT $ do p <- ask modify' $ p (<> w) pass :: Monad m => WriterT w m (a, w -> w) -> WriterT w m a pass m = WriterT $ do p <- ask (a, ww) <- unWriterT m modify' (p ww) pure a instance (Monoid w, Monad m) => W.MonadWriter w (WriterT w m) where tell = tell listen m = do aw@(_a, w) <- lift $ runWriterT m tell w pure aw pass = pass -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Fri Aug 30 02:56:32 2019 From: david.feuer at gmail.com (David Feuer) Date: Fri, 30 Aug 2019 09:56:32 +0700 Subject: [Haskell-cafe] A faithful strictly-accumulating writer In-Reply-To: References: Message-ID: Here's another version that passes the state-modifier implicitly. Is this better or worse? {-# language RankNTypes, FlexibleInstances, MultiParamTypeClasses, TypeFamilies #-} module WriterT where import qualified Control.Monad.Writer.Class as W import Control.Monad.State.Strict import Control.Applicative class WGS w s where wgs :: (w -> w) -> s -> s instance w ~ s => WGS w s where wgs = id newtype WriterT w m a = WriterT { unWriterT :: forall s. WGS w s => StateT s m a } runWriterT :: Monoid w => WriterT w m a -> m (a, w) runWriterT m = runStateT (unWriterT m) mempty instance Functor m => Functor (WriterT w m) where fmap f m = WriterT $ fmap f (unWriterT m) instance Monad m => Applicative (WriterT w m) where pure a = WriterT (pure a) liftA2 f m n = WriterT $ liftA2 f (unWriterT m) (unWriterT n) instance Monad m => Monad (WriterT w m) where m >>= f = WriterT $ unWriterT m >>= unWriterT . f instance MonadTrans (WriterT w) where lift m = WriterT $ lift $ m tell :: (Monad m, Semigroup w) => w -> WriterT w m () tell w = WriterT $ modify' $ wgs (<> w) listen :: (Monad m, Monoid w) => WriterT w m a -> WriterT w m (a, w) listen m = do aw@(_a, w) <- lift $ runWriterT m tell w pure aw pass :: Monad m => WriterT w m (a, w -> w) -> WriterT w m a pass m = WriterT $ do (a, ww) <- unWriterT m modify' (wgs ww) pure a instance (Monoid w, Monad m) => W.MonadWriter w (WriterT w m) where tell = tell listen = listen pass = pass On Fri, Aug 30, 2019 at 9:11 AM David Feuer wrote: > It's widely known that the classic WriterT tends to leak space, and that > in some cases this leak can be resolved by using StateT instead. The > implementations I've seen of this idea both use the module system to > prevent the computation from gaining unauthorized access to the state. I > believe I've found a way to avoid this. Does this look right? > > {-# language RankNTypes, FlexibleInstances, MultiParamTypeClasses #-} > > import qualified Control.Monad.Writer.Class as W > import Control.Monad.State.Strict > import Control.Monad.Reader > import Control.Applicative > > -- The key idea is that the computation > -- can't inspect the state because it doesn't know the type > newtype WriterT w m a = WriterT > { unWriterT :: forall s. ReaderT ((w -> w) -> s -> s) (StateT s m) a } > > runWriterT :: Monoid w => WriterT w m a -> m (a, w) > runWriterT m = runStateT (runReaderT (unWriterT m) id) mempty > > instance Functor m => Functor (WriterT w m) where > fmap f m = WriterT $ fmap f (unWriterT m) > > instance Monad m => Applicative (WriterT w m) where > pure a = WriterT (pure a) > liftA2 f m n = WriterT $ liftA2 f (unWriterT m) (unWriterT n) > > instance Monad m => Monad (WriterT w m) where > m >>= f = WriterT $ unWriterT m >>= unWriterT . f > > instance MonadTrans (WriterT w) where > lift m = WriterT $ lift . lift $ m > > tell :: (Monad m, Semigroup w) => w -> WriterT w m () > tell w = WriterT $ do > p <- ask > modify' $ p (<> w) > > pass :: Monad m => WriterT w m (a, w -> w) -> WriterT w m a > pass m = WriterT $ do > p <- ask > (a, ww) <- unWriterT m > modify' (p ww) > pure a > > instance (Monoid w, Monad m) => W.MonadWriter w (WriterT w m) where > tell = tell > > listen m = do > aw@(_a, w) <- lift $ runWriterT m > tell w > pure aw > > pass = pass > -------------- next part -------------- An HTML attachment was scrubbed... URL: From lysxia at gmail.com Fri Aug 30 03:42:51 2019 From: lysxia at gmail.com (Li-yao Xia) Date: Thu, 29 Aug 2019 23:42:51 -0400 Subject: [Haskell-cafe] A faithful strictly-accumulating writer In-Reply-To: References: Message-ID: <5d826b18-bf54-7a6a-0c84-8818b336f218@gmail.com> This looks like an interesting problem, but I'm a little confused about the objective. In what sense is it "faithful"? > to prevent the computation from gaining unauthorized access to the state. Does that property have a formal definition? Are we looking for a one-to-one correspondence between a "better" WriterT and the naive WriterT? What about (w -> s -> s) instead of ((w -> w) -> (s -> s))? It seems that `pass` needs the (w -> w), but if we leave `pass` aside, does that still look about right? Li-yao On 8/29/19 10:56 PM, David Feuer wrote: > Here's another version that passes the state-modifier implicitly. Is this > better or worse? > > {-# language RankNTypes, FlexibleInstances, MultiParamTypeClasses, > TypeFamilies #-} > module WriterT where > > import qualified Control.Monad.Writer.Class as W > import Control.Monad.State.Strict > import Control.Applicative > > class WGS w s where > wgs :: (w -> w) -> s -> s > > instance w ~ s => WGS w s where > wgs = id > > newtype WriterT w m a = WriterT > { unWriterT :: forall s. WGS w s => StateT s m a } > > runWriterT :: Monoid w => WriterT w m a -> m (a, w) > runWriterT m = runStateT (unWriterT m) mempty > > instance Functor m => Functor (WriterT w m) where > fmap f m = WriterT $ fmap f (unWriterT m) > > instance Monad m => Applicative (WriterT w m) where > pure a = WriterT (pure a) > liftA2 f m n = WriterT $ liftA2 f (unWriterT m) (unWriterT n) > > instance Monad m => Monad (WriterT w m) where > m >>= f = WriterT $ unWriterT m >>= unWriterT . f > > instance MonadTrans (WriterT w) where > lift m = WriterT $ lift $ m > > tell :: (Monad m, Semigroup w) => w -> WriterT w m () > tell w = WriterT $ modify' $ wgs (<> w) > > listen :: (Monad m, Monoid w) => WriterT w m a -> WriterT w m (a, w) > listen m = do > aw@(_a, w) <- lift $ runWriterT m > tell w > pure aw > > pass :: Monad m => WriterT w m (a, w -> w) -> WriterT w m a > pass m = WriterT $ do > (a, ww) <- unWriterT m > modify' (wgs ww) > pure a > > instance (Monoid w, Monad m) => W.MonadWriter w (WriterT w m) where > tell = tell > listen = listen > pass = pass > > On Fri, Aug 30, 2019 at 9:11 AM David Feuer wrote: > >> It's widely known that the classic WriterT tends to leak space, and that >> in some cases this leak can be resolved by using StateT instead. The >> implementations I've seen of this idea both use the module system to >> prevent the computation from gaining unauthorized access to the state. I >> believe I've found a way to avoid this. Does this look right? >> >> {-# language RankNTypes, FlexibleInstances, MultiParamTypeClasses #-} >> >> import qualified Control.Monad.Writer.Class as W >> import Control.Monad.State.Strict >> import Control.Monad.Reader >> import Control.Applicative >> >> -- The key idea is that the computation >> -- can't inspect the state because it doesn't know the type >> newtype WriterT w m a = WriterT >> { unWriterT :: forall s. ReaderT ((w -> w) -> s -> s) (StateT s m) a } >> >> runWriterT :: Monoid w => WriterT w m a -> m (a, w) >> runWriterT m = runStateT (runReaderT (unWriterT m) id) mempty >> >> instance Functor m => Functor (WriterT w m) where >> fmap f m = WriterT $ fmap f (unWriterT m) >> >> instance Monad m => Applicative (WriterT w m) where >> pure a = WriterT (pure a) >> liftA2 f m n = WriterT $ liftA2 f (unWriterT m) (unWriterT n) >> >> instance Monad m => Monad (WriterT w m) where >> m >>= f = WriterT $ unWriterT m >>= unWriterT . f >> >> instance MonadTrans (WriterT w) where >> lift m = WriterT $ lift . lift $ m >> >> tell :: (Monad m, Semigroup w) => w -> WriterT w m () >> tell w = WriterT $ do >> p <- ask >> modify' $ p (<> w) >> >> pass :: Monad m => WriterT w m (a, w -> w) -> WriterT w m a >> pass m = WriterT $ do >> p <- ask >> (a, ww) <- unWriterT m >> modify' (p ww) >> pure a >> >> instance (Monoid w, Monad m) => W.MonadWriter w (WriterT w m) where >> tell = tell >> >> listen m = do >> aw@(_a, w) <- lift $ runWriterT m >> tell w >> pure aw >> >> pass = pass >> > > > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. > From david.feuer at gmail.com Fri Aug 30 04:09:26 2019 From: david.feuer at gmail.com (David Feuer) Date: Fri, 30 Aug 2019 00:09:26 -0400 Subject: [Haskell-cafe] A faithful strictly-accumulating writer In-Reply-To: <5d826b18-bf54-7a6a-0c84-8818b336f218@gmail.com> References: <5d826b18-bf54-7a6a-0c84-8818b336f218@gmail.com> Message-ID: On Thu, Aug 29, 2019, 11:42 PM Li-yao Xia wrote: > This looks like an interesting problem, but I'm a little confused about > the objective. In what sense is it "faithful"? > > > to prevent the computation from gaining unauthorized access to the > state. > > Does that property have a formal definition? Are we looking for a > one-to-one correspondence between a "better" WriterT and the naive WriterT? > Exactly. They should be isomorphic as sets and "morally" isomorphic as monads. There will of course be distinctions in strictness > What about (w -> s -> s) instead of ((w -> w) -> (s -> s))? It seems > that `pass` needs the (w -> w), but if we leave `pass` aside, does that > still look about right? > Yes. That's the type I started with, and then I got to `pass` and realized it just wouldn't do the trick. -------------- next part -------------- An HTML attachment was scrubbed... URL: From zemyla at gmail.com Fri Aug 30 04:49:32 2019 From: zemyla at gmail.com (Zemyla) Date: Thu, 29 Aug 2019 23:49:32 -0500 Subject: [Haskell-cafe] A faithful strictly-accumulating writer In-Reply-To: References: <5d826b18-bf54-7a6a-0c84-8818b336f218@gmail.com> Message-ID: I wish we could separate listen and pass from the Writer monad, and eventually deprecate them. Doing so would solve so many problems. On Thu, Aug 29, 2019, 23:10 David Feuer wrote: > On Thu, Aug 29, 2019, 11:42 PM Li-yao Xia wrote: > >> This looks like an interesting problem, but I'm a little confused about >> the objective. In what sense is it "faithful"? >> >> > to prevent the computation from gaining unauthorized access to the >> state. >> >> Does that property have a formal definition? Are we looking for a >> one-to-one correspondence between a "better" WriterT and the naive >> WriterT? >> > > Exactly. They should be isomorphic as sets and "morally" isomorphic as > monads. There will of course be distinctions in strictness > > >> What about (w -> s -> s) instead of ((w -> w) -> (s -> s))? It seems >> that `pass` needs the (w -> w), but if we leave `pass` aside, does that >> still look about right? >> > > Yes. That's the type I started with, and then I got to `pass` and realized > it just wouldn't do the trick. > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mailinglists at robbertkrebbers.nl Fri Aug 30 07:49:26 2019 From: mailinglists at robbertkrebbers.nl (Robbert Krebbers) Date: Fri, 30 Aug 2019 09:49:26 +0200 Subject: [Haskell-cafe] Call for scholarship applications: PLMW @ POPL 2020 Message-ID: <615d0a68-2fb1-25ea-74d6-bf3ade07c887@robbertkrebbers.nl> CALL FOR SCHOLARSHIP APPLICATIONS (** DEADLINE: OCTOBER 7 **) ACM SIGPLAN Programming Languages Mentoring Workshop, New Orleans, Louisiana Tuesday, January 21, 2020 Co-located with POPL 2020 Web page: https://popl20.sigplan.org/home/PLMW-POPL-2020 After the success of the first eight Programming Languages Mentoring Workshops at POPL 2012-2019 we are announcing the 9th SIGPLAN Programming Languages Mentoring Workshop (PLMW), co-located with POPL 2020 and organized by Stephanie Balzer, Justin Hsu, Robbert Krebbers, and Nobuko Yoshida. The purpose of this mentoring workshop is to encourage graduate students and senior undergraduate students to pursue careers in programming language research. This workshop will bring together world leaders in programming languages research and teaching from academia and industry to provide (a) technical sessions on cutting-edge PL research and (b) mentoring sessions on how to prepare for a research career. The workshop will help students imagine how they might contribute to our research community. We especially encourage women and underrepresented minority students, and people with disabilities to attend PLMW. This workshop is part of the activities surrounding POPL, the Symposium on Principles of Programming Languages, and takes place the day before the main conference. One goal of the workshop is to make the POPL conference more accessible to newcomers. We hope that participants will stay through the entire conference. A number of sponsors (listed below) have generously donated scholarship funds for qualified students to attend PLMW. These scholarships should cover reasonable expenses (airfare, hotel, and registration fees) for attendance at both the workshop and the POPL conference. Students attending this year will get one year free student membership of SIGPLAN, unless they prefer to opt out during their application. The workshop registration is open to all. Students with alternative sources of funding are welcome as well. APPLICATION for PLMW scholarship: The scholarship application can be accessed at the following URL: https://forms.gle/dzV8ELgQUx2xfEjm9 The deadline for full consideration of funding is Monday, October 7. Selected participants will be notified by October 21. Confirmed speakers (so far): * Adriana Compagnoni, Stevens Institute of Technology * Isil Dillig, UT Austin * Derek Dreyer, MPI-SWS * Marco Gaboardi, SUNY Buffalo * Lindsey Kuper, UC Santa Cruz * Xavier Leroy, Inria Confirmed sponsors (so far): * An Anonymous Donor * NSF * ACM SIGPLAN * Amazon From david.feuer at gmail.com Fri Aug 30 15:46:04 2019 From: david.feuer at gmail.com (David Feuer) Date: Fri, 30 Aug 2019 11:46:04 -0400 Subject: [Haskell-cafe] A faithful strictly-accumulating writer In-Reply-To: References: <5d826b18-bf54-7a6a-0c84-8818b336f218@gmail.com> Message-ID: I would definitely like to see `listen` split out, since it adds a sort of introspection that can't be good for CPS-based implementations. `pass` is a rather surprising piece of the API that definitely seems to want its own subclass. Another way to express its idea is edit :: (w -> w) -> WriterT w m () This is equally powerful: edit f = pass $ pure ((), f) pass m = do (a, f) <- m edit f pure a The essence of edit/pass is that it adds the ability to make arbitrary modifications to the "log". That excludes instances for which the log itself is not accessible at all. instance MonadWriter String IO where tell = hPutStr stderr On Fri, Aug 30, 2019, 12:49 AM Zemyla wrote: > I wish we could separate listen and pass from the Writer monad, and > eventually deprecate them. Doing so would solve so many problems. > > On Thu, Aug 29, 2019, 23:10 David Feuer wrote: > >> On Thu, Aug 29, 2019, 11:42 PM Li-yao Xia wrote: >> >>> This looks like an interesting problem, but I'm a little confused about >>> the objective. In what sense is it "faithful"? >>> >>> > to prevent the computation from gaining unauthorized access to the >>> state. >>> >>> Does that property have a formal definition? Are we looking for a >>> one-to-one correspondence between a "better" WriterT and the naive >>> WriterT? >>> >> >> Exactly. They should be isomorphic as sets and "morally" isomorphic as >> monads. There will of course be distinctions in strictness >> >> >>> What about (w -> s -> s) instead of ((w -> w) -> (s -> s))? It seems >>> that `pass` needs the (w -> w), but if we leave `pass` aside, does that >>> still look about right? >>> >> >> Yes. That's the type I started with, and then I got to `pass` and >> realized it just wouldn't do the trick. >> _______________________________________________ >> Haskell-Cafe mailing list >> To (un)subscribe, modify options or view archives go to: >> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >> Only members subscribed via the mailman list are allowed to post. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Fri Aug 30 16:17:13 2019 From: david.feuer at gmail.com (David Feuer) Date: Fri, 30 Aug 2019 12:17:13 -0400 Subject: [Haskell-cafe] A faithful strictly-accumulating writer In-Reply-To: References: <5d826b18-bf54-7a6a-0c84-8818b336f218@gmail.com> Message-ID: Hmm... that implementation of `pass` isn't quite right for lazy WriterT. I guess it needs to be pass m = do ~(a, f) <- m edit f pure a On Fri, Aug 30, 2019, 11:46 AM David Feuer wrote: > I would definitely like to see `listen` split out, since it adds a sort of > introspection that can't be good for CPS-based implementations. > > `pass` is a rather surprising piece of the API that definitely seems to > want its own subclass. Another way to express its idea is > > edit :: (w -> w) -> WriterT w m () > > This is equally powerful: > > edit f = pass $ pure ((), f) > pass m = do > (a, f) <- m > edit f > pure a > > The essence of edit/pass is that it adds the ability to make arbitrary > modifications to the "log". That excludes instances for which the log > itself is not accessible at all. > > instance MonadWriter String IO where > tell = hPutStr stderr > > On Fri, Aug 30, 2019, 12:49 AM Zemyla wrote: > >> I wish we could separate listen and pass from the Writer monad, and >> eventually deprecate them. Doing so would solve so many problems. >> >> On Thu, Aug 29, 2019, 23:10 David Feuer wrote: >> >>> On Thu, Aug 29, 2019, 11:42 PM Li-yao Xia wrote: >>> >>>> This looks like an interesting problem, but I'm a little confused about >>>> the objective. In what sense is it "faithful"? >>>> >>>> > to prevent the computation from gaining unauthorized access to the >>>> state. >>>> >>>> Does that property have a formal definition? Are we looking for a >>>> one-to-one correspondence between a "better" WriterT and the naive >>>> WriterT? >>>> >>> >>> Exactly. They should be isomorphic as sets and "morally" isomorphic as >>> monads. There will of course be distinctions in strictness >>> >>> >>>> What about (w -> s -> s) instead of ((w -> w) -> (s -> s))? It seems >>>> that `pass` needs the (w -> w), but if we leave `pass` aside, does that >>>> still look about right? >>>> >>> >>> Yes. That's the type I started with, and then I got to `pass` and >>> realized it just wouldn't do the trick. >>> _______________________________________________ >>> Haskell-Cafe mailing list >>> To (un)subscribe, modify options or view archives go to: >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >>> Only members subscribed via the mailman list are allowed to post. >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Fri Aug 30 16:40:46 2019 From: david.feuer at gmail.com (David Feuer) Date: Fri, 30 Aug 2019 12:40:46 -0400 Subject: [Haskell-cafe] A faithful strictly-accumulating writer In-Reply-To: References: <5d826b18-bf54-7a6a-0c84-8818b336f218@gmail.com> Message-ID: No, that's not quite right either (too lazy this time). The idea is morally right, but I guess it doesn't quite work out for strictness. Anyway, this is all a side track. On Fri, Aug 30, 2019, 12:17 PM David Feuer wrote: > Hmm... that implementation of `pass` isn't quite right for lazy WriterT. I > guess it needs to be > > pass m = do > ~(a, f) <- m > edit f > pure a > > On Fri, Aug 30, 2019, 11:46 AM David Feuer wrote: > >> I would definitely like to see `listen` split out, since it adds a sort >> of introspection that can't be good for CPS-based implementations. >> >> `pass` is a rather surprising piece of the API that definitely seems to >> want its own subclass. Another way to express its idea is >> >> edit :: (w -> w) -> WriterT w m () >> >> This is equally powerful: >> >> edit f = pass $ pure ((), f) >> pass m = do >> (a, f) <- m >> edit f >> pure a >> >> The essence of edit/pass is that it adds the ability to make arbitrary >> modifications to the "log". That excludes instances for which the log >> itself is not accessible at all. >> >> instance MonadWriter String IO where >> tell = hPutStr stderr >> >> On Fri, Aug 30, 2019, 12:49 AM Zemyla wrote: >> >>> I wish we could separate listen and pass from the Writer monad, and >>> eventually deprecate them. Doing so would solve so many problems. >>> >>> On Thu, Aug 29, 2019, 23:10 David Feuer wrote: >>> >>>> On Thu, Aug 29, 2019, 11:42 PM Li-yao Xia wrote: >>>> >>>>> This looks like an interesting problem, but I'm a little confused >>>>> about >>>>> the objective. In what sense is it "faithful"? >>>>> >>>>> > to prevent the computation from gaining unauthorized access to the >>>>> state. >>>>> >>>>> Does that property have a formal definition? Are we looking for a >>>>> one-to-one correspondence between a "better" WriterT and the naive >>>>> WriterT? >>>>> >>>> >>>> Exactly. They should be isomorphic as sets and "morally" isomorphic as >>>> monads. There will of course be distinctions in strictness >>>> >>>> >>>>> What about (w -> s -> s) instead of ((w -> w) -> (s -> s))? It seems >>>>> that `pass` needs the (w -> w), but if we leave `pass` aside, does >>>>> that >>>>> still look about right? >>>>> >>>> >>>> Yes. That's the type I started with, and then I got to `pass` and >>>> realized it just wouldn't do the trick. >>>> _______________________________________________ >>>> Haskell-Cafe mailing list >>>> To (un)subscribe, modify options or view archives go to: >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >>>> Only members subscribed via the mailman list are allowed to post. >>> >>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From john at yourdigitalvoice.net Sat Aug 31 09:03:30 2019 From: john at yourdigitalvoice.net (John Sinclair) Date: Sat, 31 Aug 2019 14:33:30 +0530 Subject: [Haskell-cafe] [CFP] Final Day for submissions to Functional Conf 2019 in Bengaluru! Message-ID: Are you using Haskell in innovative ways? Do you have expertise the community would benefit from? Functional Conf 2019 is India's premier Functional programming conference, and we would love to hear from you! Submit your session proposal here: https://confng.in/zmRYXh7N Hurry! Submissions close today (Aug 31)! Functional Conf is the premiere event for Functional programmers in India. Our goal is to support the community with access to high quality speakers, who are innovating in this field. https://twitter.com/FnConf https://www.linkedin.com/showcase/functional-conf -------------- next part -------------- An HTML attachment was scrubbed... URL: From john at coherentgraphics.co.uk Sat Aug 31 16:13:54 2019 From: john at coherentgraphics.co.uk (John Whitington) Date: Sat, 31 Aug 2019 17:13:54 +0100 Subject: [Haskell-cafe] Book reviewers wanted Message-ID: Hello, I've prepared a book "Haskell from the Very Beginning" in the same manner as my earlier "OCaml from the Very Beginning". It would be useful to find some people to look it over before release. I did this with the OCaml book, and it improved it markedly. I'm particularly looking for people who have taught or learned Haskell as a first programming language (either in an academic setting or not). I should point out that the book has already benefited from a full, paid, technical review, so you would not be being used as a substitute for that. Do drop me an email if you're interested. There would be, of course, no obligation. Thanks, John -- John Whitington Director, Coherent Graphics Ltd From greg7mdp at gmail.com Sat Aug 31 17:19:03 2019 From: greg7mdp at gmail.com (Gregory Popovitch) Date: Sat, 31 Aug 2019 13:19:03 -0400 Subject: [Haskell-cafe] Book reviewers wanted In-Reply-To: References: Message-ID: <998846FC36F343A79E3C2F7BD6FEB6DF@gregava> Hi John, I'm far from a Haskell expert, but I think I would enjoy doing this. Thanks, greg -----Original Message----- From: Haskell-Cafe [mailto:haskell-cafe-bounces at haskell.org] On Behalf Of John Whitington Sent: Saturday, August 31, 2019 12:14 PM To: haskell-cafe at haskell.org Subject: [Haskell-cafe] Book reviewers wanted Hello, I've prepared a book "Haskell from the Very Beginning" in the same manner as my earlier "OCaml from the Very Beginning". It would be useful to find some people to look it over before release. I did this with the OCaml book, and it improved it markedly. I'm particularly looking for people who have taught or learned Haskell as a first programming language (either in an academic setting or not). I should point out that the book has already benefited from a full, paid, technical review, so you would not be being used as a substitute for that. Do drop me an email if you're interested. There would be, of course, no obligation. Thanks, John -- John Whitington Director, Coherent Graphics Ltd _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post. From leiva.steven at gmail.com Sat Aug 31 17:24:55 2019 From: leiva.steven at gmail.com (Steven Leiva) Date: Sat, 31 Aug 2019 12:24:55 -0500 Subject: [Haskell-cafe] Book reviewers wanted In-Reply-To: <998846FC36F343A79E3C2F7BD6FEB6DF@gregava> References: <998846FC36F343A79E3C2F7BD6FEB6DF@gregava> Message-ID: I think I’d be able to help. On Sat, Aug 31, 2019 at 12:19 PM Gregory Popovitch wrote: > Hi John, > > I'm far from a Haskell expert, but I think I would enjoy doing this. > > Thanks, > > greg > > -----Original Message----- > From: Haskell-Cafe [mailto:haskell-cafe-bounces at haskell.org] On Behalf Of > John Whitington > Sent: Saturday, August 31, 2019 12:14 PM > To: haskell-cafe at haskell.org > Subject: [Haskell-cafe] Book reviewers wanted > > Hello, > > I've prepared a book "Haskell from the Very Beginning" in the same manner > as > my earlier "OCaml from the Very Beginning". > > It would be useful to find some people to look it over before release. I > did > this with the OCaml book, and it improved it markedly. I'm particularly > looking for people who have taught or learned Haskell as a first > programming > language (either in an academic setting or not). > > I should point out that the book has already benefited from a full, paid, > technical review, so you would not be being used as a substitute for that. > > Do drop me an email if you're interested. There would be, of course, no > obligation. > > Thanks, > > John > > -- > John Whitington > Director, Coherent Graphics Ltd > > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. > > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -- Sent from Gmail Mobile -------------- next part -------------- An HTML attachment was scrubbed... URL: From charlesparkerii at gmail.com Sat Aug 31 17:29:02 2019 From: charlesparkerii at gmail.com (Charles Parker) Date: Sat, 31 Aug 2019 13:29:02 -0400 Subject: [Haskell-cafe] Book reviewers wanted In-Reply-To: References: <998846FC36F343A79E3C2F7BD6FEB6DF@gregava> Message-ID: John, Count me in. I would like to help also. Thank you. -Charles Parker, II MBA/MSA/JD/LLM/PhD (IT) IMPORTANT LEGAL NOTICE: The foregoing message (including all attachments) may contain CONFIDENTIAL and/or PRIVILEGED INFORMATION and it is for the use of the intended recipient(s) only. It is covered by the Electronic Communications Privacy Act, 18 U.S.C. Sections 2510 - 2521. It may contain CONFIDENTIAL and/or PRIVILEGED INFORMATION and may also be protected by other PRIVILEGE. If you are not the intended recipient of this message, you are hereby notified that any retention, dissemination, distribution or copying of this communication in any manner whatsoever is strictly prohibited and subject to CRIMINAL and/or CIVIL SANCTIONS. Please reply to the sender (charlesparkerii at gmail.com ) that you have received this message in error, then permanently delete it and destroy all of its contents immediately including printed, photographed or written copies in your possession or in the possession of others that you may have sent this communication to. Thank you for your time and concern. CIRCULAR 203 NOTICE: To comply with U.S. Treasury Department and Internal Revenue Service laws and regulations, we are required to advise you that, unless expressly stated otherwise, any U.S. federal tax advice contained in this e-mail including any attachments to this e-mail, is not intended or written to be used and cannot be used, by any person, for the purpose of (i) avoiding penalties under the U.S. Internal Revenue Code, or (ii) promoting, marketing or recommending to another party any transaction or matter addressed in this e-mail or attachments. No Contract Intended. Neither the e-mail signature block nor the email address contained in this transmission constitutes a signed writing for purposes of a binding contract or a signature under the Uniform Electronic Transactions Act. The sender does not intend to conduct any transactions by electronic means. Any language contained in this e-mail relating to negotiations is preliminary in nature and is not intended to form an agreement or contract. On Sat, Aug 31, 2019 at 1:25 PM Steven Leiva wrote: > I think I’d be able to help. > > On Sat, Aug 31, 2019 at 12:19 PM Gregory Popovitch > wrote: > >> Hi John, >> >> I'm far from a Haskell expert, but I think I would enjoy doing this. >> >> Thanks, >> >> greg >> >> -----Original Message----- >> From: Haskell-Cafe [mailto:haskell-cafe-bounces at haskell.org] On Behalf Of >> John Whitington >> Sent: Saturday, August 31, 2019 12:14 PM >> To: haskell-cafe at haskell.org >> Subject: [Haskell-cafe] Book reviewers wanted >> >> Hello, >> >> I've prepared a book "Haskell from the Very Beginning" in the same manner >> as >> my earlier "OCaml from the Very Beginning". >> >> It would be useful to find some people to look it over before release. I >> did >> this with the OCaml book, and it improved it markedly. I'm particularly >> looking for people who have taught or learned Haskell as a first >> programming >> language (either in an academic setting or not). >> >> I should point out that the book has already benefited from a full, paid, >> technical review, so you would not be being used as a substitute for that. >> >> Do drop me an email if you're interested. There would be, of course, no >> obligation. >> >> Thanks, >> >> John >> >> -- >> John Whitington >> Director, Coherent Graphics Ltd >> >> _______________________________________________ >> Haskell-Cafe mailing list >> To (un)subscribe, modify options or view archives go to: >> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >> Only members subscribed via the mailman list are allowed to post. >> >> _______________________________________________ >> Haskell-Cafe mailing list >> To (un)subscribe, modify options or view archives go to: >> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe >> Only members subscribed via the mailman list are allowed to post. > > -- > Sent from Gmail Mobile > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -------------- next part -------------- An HTML attachment was scrubbed... URL: