Earlier quoted context omitted.
Not that complicated even in C++ template auto map(Func && func, Lists &&... lists) -> std::vector ::type::value_type>()...))>;
> std::declval ::type::value_type>() Yes, nothing hard to understand or discover about that at all...
Cold Showers: For when people get too hyped up about things
231–240 of 243 posts
Re: Cold Showers: For when people get too hyped up about things
#232Earlier quoted context omitted.
Yeah it's not at all complicated in Haskell. I'm not sure what GP is talking about.
I replied to the parent as well, but not only is the solution the parent showed significantly more complex than the CL version, I'm not even sure it actually does what I asked. More explicitly, the expression there seems to rely on knowing the arity of the function and the number of lists at compile time. Basically, I was asking for a function cl_map such that: cl_map foo [xs:[ys:[zs:...]]] = foo xs ys zs ... Edit: f…
> traverse_ print (sequenceA [ZipList [1,2], ZipList [3,4]])
[1,3]
[2,4]Re: Cold Showers: For when people get too hyped up about things
#233Earlier quoted context omitted.
I replied to the parent as well, but not only is the solution the parent showed significantly more complex than the CL version, I'm not even sure it actually does what I asked. More explicitly, the expression there seems to rely on knowing the arity of the function and the number of lists at compile time. Basically, I was asking for a function cl_map such that: cl_map foo [xs:[ys:[zs:...]]] = foo xs ys zs ... Edit: f…
Sure it's possible in Haskell. I'm not sure where in that paper you got the impression it isn't. Of course one can't define variadic functions in Haskell, but that's a more fundamental difference from Clojure, not a "code pattern that [is] safe and easy to do with dynamic typing, but impossible with simple type systems or more complex with more advanced type system." > traverse_ print (sequenceA [ZipList [1,2], ZipLi…
Basically, instead of your example I would like to do something like this:
> cl_map (+) [ZipList [1,2,3], ZipList [4,5,6]]
[5,7,9]
> cl_map (+ 3) [ZipList [1,2,3]]
[4,5,6]
> cl_map max3 [ZipList [1,2], ZipList [3,4], ZipList [5,6]] where max3 x y z = max x (max y z)
[5, 6]
Can this be done? What is the type of cl_map?Note: If this doesn't work with ZipList, that's ok - the important part is being able to supply the function at runtime. Also, please don't assume that the function is associative or anything like that - it's an arbitrary function of N parameters.
Re: Cold Showers: For when people get too hyped up about things
#234Earlier quoted context omitted.
Sure it's possible in Haskell. I'm not sure where in that paper you got the impression it isn't. Of course one can't define variadic functions in Haskell, but that's a more fundamental difference from Clojure, not a "code pattern that [is] safe and easy to do with dynamic typing, but impossible with simple type systems or more complex with more advanced type system." > traverse_ print (sequenceA [ZipList [1,2], ZipLi…
As far as I can tell, your example calls a unary function on each element of a list of lists. It's solving the variadic part of map, but not the part where I can call an N-ary function with each element of N lists. Basically, instead of your example I would like to do something like this: > cl_map (+) [ZipList [1,2,3], ZipList [4,5,6]] [5,7,9] > cl_map (+ 3) [ZipList [1,2,3]] [4,5,6] > cl_map max3 [ZipList [1,2], Zip…
> (+) ZipList [1,2,3] ZipList [4,5,6]
ZipList {getZipList = [5,7,9]}
> (+3) ZipList [1,2,3]
ZipList {getZipList = [4,5,6]}
> let max3 x y z = max x (max y z)
> max3 ZipList [1,2] ZipList [3,4] ZipList [5,6]
ZipList {getZipList = [5,6]}
If you want to use "functions unknown at runtime that could take
any number of arguments" then you'll have to pass the arguments
in a list. Of course these can crash at runtime, which
Haskellers wouldn't be happy with given an alternative, but
hey-ho, let's see where we get. > let unsafePlus [x, y] = x + y
> fmap unsafePlus (sequenceA [ZipList [1,2,3], ZipList [4,5,6]])
ZipList {getZipList = [5,7,9]}
> let unsafePlus3 [x] = x + 3
> fmap unsafePlus3 (sequenceA [ZipList [1,2,3]])
ZipList {getZipList = [4,5,6]}
> unsafeMax3 [x, y, z] = x `max` y `max` z
> fmap unsafeMax3 (sequenceA [ZipList [1,2], ZipList [3,4], ZipList [5,6]])
ZipList {getZipList = [5,6]}
So the answer to your question is that cl_map :: ([a] -> b) -> [ZipList a] -> ZipList b
cl_map f = fmap f . sequenceA
except you don't actually want all the elements of the list to be
of the same type, you want them to be of dynamic type, so let's
just make them Dynamic. > let unwrap x = fromDyn x (error "Type error")
>
> let unsafeGreeting [name, authorized] =
> if unwrap authorized then "Welcome, " ++ unwrap name
> else "UNAUTHORIZED!"
>
> fmap unsafeGreeting (sequenceA [ZipList [toDyn "tome", toDyn "simiones", toDyn "pg"]
> , ZipList [toDyn True, toDyn True, toDyn False]])
ZipList {getZipList = ["Welcome, tome","Welcome, simiones","UNAUTHORIZED!"]}
and the type of cl_map becomes cl_map :: ([Dynamic] -> b) -> [ZipList Dynamic] -> ZipList b
cl_map f = fmap f . sequenceA
One could polish this up a bit and make a coherent ecosystem out
of it, but Haskell programmers hardly ever use Dynamic. We just
don't come across the situations where Clojurists seem to think
it's necessary.Re: Cold Showers: For when people get too hyped up about things
#235Earlier quoted context omitted.
As far as I can tell, your example calls a unary function on each element of a list of lists. It's solving the variadic part of map, but not the part where I can call an N-ary function with each element of N lists. Basically, instead of your example I would like to do something like this: > cl_map (+) [ZipList [1,2,3], ZipList [4,5,6]] [5,7,9] > cl_map (+ 3) [ZipList [1,2,3]] [4,5,6] > cl_map max3 [ZipList [1,2], Zip…
The functions in those examples have fixed numbers of arguments, so one would use the original formulation shown by Tyr42. > (+) ZipList [1,2,3] ZipList [4,5,6] ZipList {getZipList = [5,7,9]} > (+3) ZipList [1,2,3] ZipList {getZipList = [4,5,6]} > let max3 x y z = max x (max y z) > max3 ZipList [1,2] ZipList [3,4] ZipList [5,6] ZipList {getZipList = [5,6]} If you want to use "functions unknown at runtime that could t…
It's nice that Haskell does offer a way to circumvent the type system to write somewhat dynamic code, but it's a shame that in order to write a relatively simple function we need to resort to that.
Note that the type of cl_map is perfectly static. It would be `Integer N => (a_0 ->... a_N -> r) -> [a_0] ->... [a_N] -> [r]` assuming some fictitious syntax.
Re: Cold Showers: For when people get too hyped up about things
#236Earlier quoted context omitted.
The functions in those examples have fixed numbers of arguments, so one would use the original formulation shown by Tyr42. > (+) ZipList [1,2,3] ZipList [4,5,6] ZipList {getZipList = [5,7,9]} > (+3) ZipList [1,2,3] ZipList {getZipList = [4,5,6]} > let max3 x y z = max x (max y z) > max3 ZipList [1,2] ZipList [3,4] ZipList [5,6] ZipList {getZipList = [5,6]} If you want to use "functions unknown at runtime that could t…
So in the end, as I claimed initially, this function can't be written in a simple, safe way in Haskell; and as the article I linked claims, Haskell's type system can't encode the type of the cl_map function. It's nice that Haskell does offer a way to circumvent the type system to write somewhat dynamic code, but it's a shame that in order to write a relatively simple function we need to resort to that. Note that the…
Steady on! You posed a question and I gave an answer. You weren't happy with that answer. I think it's a bit premature to conclude that "this function can't be written in a simple, safe way in Haskell".
> as the article I linked claims, Haskell's type system can't encode the type of the cl_map function.
Could you say where you see that claim in the article? I can see three mentions of "Haskell" in the body, two of them mentioning that one researcher's particular implementation doesn't handle this case, but not a claim that it can't be done.
> Note that the type of cl_map is perfectly static. It would be `Integer N => (a_0 ->... a_N -> r) -> [a_0] ->... [a_N] -> [r]` assuming some fictitious syntax.
OK, fine, it's a bit clearer now what you are looking for. How about this:
> cl_map (uncurry (+)) ([1,2,3], [4,5,6])
[5,7,9]
> cl_map (+3) [1,2,3]
[4,5,6]
> let max3 (x, y, z) = x `max` y `max` z
> cl_map max3 ([1,2], [3,4], [5,6])
[5,6]
Notice that the function arguments are have different,
statically-known types! The type of this miracle function? cl_map :: Default Zipper a b => (b -> r) -> a -> [r]
And the implementation? -- Type definition
newtype Zipper a b = Zipper { unZipper :: a -> ZipList b } deriving Functor
-- Instance definition
instance a ~ b => D.Default Zipper [a] b where def = Zipper ZipList
-- These three instances are in principle derivable
instance P.Profunctor Zipper where
dimap f g = Zipper . P.dimap f (fmap g) . unZipper
instance Applicative (Zipper a) where
pure = Zipper . pure . pure
f x = Zipper (liftA2 () (unZipper f) (unZipper x))
instance PP.ProductProfunctor Zipper where
purePP = pure
(****) = ()
Given that the only two lines that actually matter are newtype Zipper a b = Zipper { unZipper :: a -> ZipList b } deriving Functor
instance a ~ b => D.Default Zipper [a] b where def = Zipper ZipList
and the rest are boiler plate that could be auto-derived, I think this
is pretty satisfactory. What do you think?Re: Cold Showers: For when people get too hyped up about things
#237I love that sqlite article. It seems like "everyone" is certain that sqlite can only be used for up to a single query per second, anything more and you need to spin up a triple sharded postgres or Hadoop cluster because it 'needs to scale'. I love being able to show that study, if you properly architect your sqlite system and am willing to purchase hardware, you can go a long long way, much further than almost all co…
SQLite is incredible. If you are struggling to beat the "one query per second" meme, try the following 2 things: 1. Only use a single connection for all access. Open the database one time at startup. SQLite operates in serialized mode by default, so the only time you need to lock is when you are trying to obtain the LastInsertRowId or perform explicit transactions across multiple rows. Trying to use the one connectio…
Re: Cold Showers: For when people get too hyped up about things
#238Earlier quoted context omitted.
So in the end, as I claimed initially, this function can't be written in a simple, safe way in Haskell; and as the article I linked claims, Haskell's type system can't encode the type of the cl_map function. It's nice that Haskell does offer a way to circumvent the type system to write somewhat dynamic code, but it's a shame that in order to write a relatively simple function we need to resort to that. Note that the…
> So in the end, as I claimed initially, this function can't be > written in a simple, safe way in Haskell Steady on! You posed a question and I gave an answer. You weren't happy with that answer. I think it's a bit premature to conclude that "this function can't be written in a simple, safe way in Haskell". > as the article I linked claims, Haskell's type system can't encode the type of the cl_map function. Could yo…
Still, you haven't written exactly the function I was asking for. You require a manual, compile-time step of transforming the N-ary function to a unary function taking a tuple. Still, it's impressive that this can define variable-length, variable-type tuples. Unfortunately I am not able at all to follow your solution, as it's using too many types that I'm not familiar with, and it seems to require some external packages, so I can't easily try it out in an online compiler to understand it better (as I have been doing so far).
Either way, I would say we are well outside the limits of an easy to understand way of specifying this kind of function - even if you are only showing 2 lines of code, it seems that your definition requires, outside of lists and functions (the objects we intended to work with): ZipList, Default, Functor, Profunctor, ProductProfunctor, Applicative, and a helper type. Even if these were derivable, someone seeking to write this function would still need to be aware of all of these types, some of which are not even part of the standard library; and of the way they work together to magically produce the relatively simple task they had set out to do.
> Could you say where you see that claim in the article?
The claim is presented implicitly: for one, they conjecture that, were Haskell or SML to "pragmatically support" such a feature, it would be used more often (offering as argument the observation that both Haskell's and SML's standard libraries define functions that differ only in the arity of their arguments, such as zipWith/zipWith3 in Haskell). This implies that, to their knowledge, it is not pragmatically possible to implement this in Haskell.
Similarly, given that in their "Related Works" section they don't identify any complete implementation of variadic polymorphism, it can be assumed that they claim at least not to have found one.
Re: Cold Showers: For when people get too hyped up about things
#239Earlier quoted context omitted.
> So in the end, as I claimed initially, this function can't be > written in a simple, safe way in Haskell Steady on! You posed a question and I gave an answer. You weren't happy with that answer. I think it's a bit premature to conclude that "this function can't be written in a simple, safe way in Haskell". > as the article I linked claims, Haskell's type system can't encode the type of the cl_map function. Could yo…
First of all, thank you for bearing with me this long! Still, you haven't written exactly the function I was asking for. You require a manual, compile-time step of transforming the N-ary function to a unary function taking a tuple. Still, it's impressive that this can define variable-length, variable-type tuples. Unfortunately I am not able at all to follow your solution, as it's using too many types that I'm not fam…
Try this. It's a full working program. The packages it depends on are "profunctors" and "product-profunctors".
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
module MyExample where
import qualified Data.Profunctor as P
import qualified Data.Profunctor.Product as PP
import qualified Data.Profunctor.Product.Default as D
newtype Zipper a b = Zipper { unZipper :: Traverse ZipList a b }
deriving Functor
instance a ~ b => D.Default Zipper [a] b where
def = Zipper (P.dimap ZipList id D.def)
instance P.Profunctor Zipper where
dimap f g = Zipper . P.dimap f g . unZipper
instance Applicative (Zipper a) where
pure = Zipper . pure
f x = Zipper (() (unZipper f) (unZipper x))
instance PP.ProductProfunctor Zipper where
purePP = pure
(****) = ()
cl_map :: D.Default Zipper a b => (b -> r) -> a -> [r]
cl_map f = getZipList . fmap f . runTraverse (unZipper D.def)Re: Cold Showers: For when people get too hyped up about things
#240Earlier quoted context omitted.
> So in the end, as I claimed initially, this function can't be > written in a simple, safe way in Haskell Steady on! You posed a question and I gave an answer. You weren't happy with that answer. I think it's a bit premature to conclude that "this function can't be written in a simple, safe way in Haskell". > as the article I linked claims, Haskell's type system can't encode the type of the cl_map function. Could yo…
First of all, thank you for bearing with me this long! Still, you haven't written exactly the function I was asking for. You require a manual, compile-time step of transforming the N-ary function to a unary function taking a tuple. Still, it's impressive that this can define variable-length, variable-type tuples. Unfortunately I am not able at all to follow your solution, as it's using too many types that I'm not fam…
I'm afraid I'm now completely stumped about what you're asking for. If you have a function with a known arity and want to apply it to a known number of arguments then you can use the original formulation:
f args1 args 2 ... argsN
You then asked what happens for unknown numbers of arguments, so I produced a solution that works with lists, which isn't very Haskelly, but does the job. After that you said you wanted something with a more specific type, so I came up with the answer that works generally over tuples (or indeed any type that contains a sequence of arguments). That's not satisfactory either! It seems you literally want a function with type `Integer N => (a_0 ->... a_N -> r) -> [a_0] ->... [a_N] -> [r]`. Well, I don't know how to do that in Haskell -- maybe my most recent solution extends to that -- but nor do I know why you'd want to do that! If you have a known number of arguments the first solution works fine. If you have an unknown number of arguments then you must have them all together in one datastructure, so the most recent solution works fine. Haskellers would be very happy with either of those and I don't see how we're missing out on programming convenience because of that. Maybe you could elaborate?