Micah Cowan | 26 Jul 23:08 2013

Sneaky method for var-arg fns?

So, just for fun, I came up with a way to abuse the language in order to
define a "function" whose argument is optional:

> -- dirty-trick.hs - A sneaky way to do var args fns in Haskell
> 
> {-# LANGUAGE FlexibleInstances #-}
> 
> class Hello a where
>     hello :: a
> 
> instance Hello (String -> String) where
>     hello = (\str -> "Hello " ++ str)
> 
> instance Hello String where
>     hello = hello "World"

In ghci,

  putStrLn $ hello

gives "Hello World", while

  putStrLn $ hello "There"

gives "Hello".

.

I was wondering if there was a way to do it in "pure" Haskell (i.e., no
GHC pragmas required), and also the specific reason for why the above
(Continue reading)

Tikhon Jelvis | 26 Jul 23:12 2013
Picon

Re: Sneaky method for var-arg fns?

Take a look at Text.Printf which takes this idea even further with its printf function, which can accept an arbitrary number of arguments. This is achieved by basically using your approach but with a recursive instance.

On Jul 26, 2013 10:10 PM, "Micah Cowan" <micah <at> cowan.name> wrote:
So, just for fun, I came up with a way to abuse the language in order to
define a "function" whose argument is optional:

> -- dirty-trick.hs - A sneaky way to do var args fns in Haskell
>
> {-# LANGUAGE FlexibleInstances #-}
>
> class Hello a where
>     hello :: a
>
> instance Hello (String -> String) where
>     hello = (\str -> "Hello " ++ str)
>
> instance Hello String where
>     hello = hello "World"

In ghci,

  putStrLn $ hello

gives "Hello World", while

  putStrLn $ hello "There"

gives "Hello".

.

I was wondering if there was a way to do it in "pure" Haskell (i.e., no
GHC pragmas required), and also the specific reason for why the above
example doesn't work without the pragma (I think it's just that in
general a -> b is not syntactically allowed for type specifiers within
instance declarations)?

I'm also interested in alternative approaches to creating
variable-argument functions, if there are any.

.

If anyone's curious, this was prompted by a discussion with a friend
(copied), about Haskell and Clojure. He mentioned that Clojure can
accept variable arguments, though AFAICT all Clojure functions basically
act like they take a list (that supports variable types), so accepting
an empty argument list is a bit analogous to Haskell accepting an empty
list, rather than no arguments.

Part of the reason Haskell can't really take "variable arguments" is
that all Haskell functions really just take one argument. But I figured
you could use the contextually expected type to decide whether to return
a simple value (not /technically/ a function in that case), or a function
expecting further arguments, which could then be extended to define a
function taking any arbitrary number of arguments.

Cheers!
-mjc

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Mateusz Kowalczyk | 26 Jul 23:23 2013
Picon

Re: Sneaky method for var-arg fns?


On 26/07/13 22:08, Micah Cowan wrote:
> So, just for fun, I came up with a way to abuse the language in
> order to define a "function" whose argument is optional:
> 
>> -- dirty-trick.hs - A sneaky way to do var args fns in Haskell
>> 
>> {-# LANGUAGE FlexibleInstances #-}
>> 
>> class Hello a where hello :: a
>> 
>> instance Hello (String -> String) where hello = (\str -> "Hello "
>> ++ str)
>> 
>> instance Hello String where hello = hello "World"
> 
> In ghci,
> 
> putStrLn $ hello
> 
> gives "Hello World", while
> 
> putStrLn $ hello "There"
> 
> gives "Hello".
> 
> .
> 
> I was wondering if there was a way to do it in "pure" Haskell
> (i.e., no GHC pragmas required), and also the specific reason for
> why the above example doesn't work without the pragma (I think it's
> just that in general a -> b is not syntactically allowed for type
> specifiers within instance declarations)?
> 
> I'm also interested in alternative approaches to creating 
> variable-argument functions, if there are any.
> 
> .
> 
> If anyone's curious, this was prompted by a discussion with a
> friend (copied), about Haskell and Clojure. He mentioned that
> Clojure can accept variable arguments, though AFAICT all Clojure
> functions basically act like they take a list (that supports
> variable types), so accepting an empty argument list is a bit
> analogous to Haskell accepting an empty list, rather than no
> arguments.
> 
> Part of the reason Haskell can't really take "variable arguments"
> is that all Haskell functions really just take one argument. But I
> figured you could use the contextually expected type to decide
> whether to return a simple value (not /technically/ a function in
> that case), or a function expecting further arguments, which could
> then be extended to define a function taking any arbitrary number
> of arguments.
> 
> Cheers! -mjc
> 
> _______________________________________________ Haskell-Cafe
> mailing list Haskell-Cafe <at> haskell.org 
> http://www.haskell.org/mailman/listinfo/haskell-cafe
> 
You might be interested in Oleg's
http://okmij.org/ftp/Haskell/polyvariadic.html

--

-- 
Mateusz K.
Brandon Allbery | 27 Jul 00:40 2013
Picon

Re: Sneaky method for var-arg fns?

On Fri, Jul 26, 2013 at 5:08 PM, Micah Cowan <micah <at> cowan.name> wrote:
I was wondering if there was a way to do it in "pure" Haskell (i.e., no
GHC pragmas required), and also the specific reason for why the above
example doesn't work without the pragma (I think it's just that in
general a -> b is not syntactically allowed for type specifiers within
instance declarations)?

The error message you get without the pragma tells you exactly what's wrong, and that's not it.

Standard Haskell is *very* conservative about what it allows in an instance declaration; you may not have literal types, nor may you repeat a type variable, only things of the form (Type var1 var2 ...) are permitted. (The (String -> String) is not syntactically a problem; it's read as ((->) String String) which would conform *if* it didn't use literal types. You can verify this by rephrasing it in prefix form --- note the error message uses the infix form even if you phrase it as a prefix!) This is widely seen as unnecessarily restrictive.

--
brandon s allbery kf8nh                               sine nomine associates
allbery.b <at> gmail.com                                  ballbery <at> sinenomine.net
unix, openafs, kerberos, infrastructure, xmonad        http://sinenomine.net
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Gmane