Odd behavior with Num instance for lists (was: f^n for functional iteration)

On Fri, Dec 13, 2013 at 8:59 AM, Antonio Nikishaev
The previous exchange prompted me to whip up a Num instance for lists: instance Num a => Num [a] where negate = fmap negate (+) = zipWith (+) (*) = zipWith (+) fromInteger x = [fromInteger x] abs = fmap abs signum = fmap signum It mostly behaves how one would expect: let a = [1,2,3] ghci> let b = [4,5,6,7] ghci> a + b [5,7,9] ghci> 1 + a [2] I was wondering whey `1 + a` succeeds. At first I thought it could be the `fromInteger` definition, but this explanation were true, I should be able to add integers and doubles freely, which I can't: ghci> fromInteger (1::Integer) + (1.0::Double) 2.0 ghci> (1::Integer) + (1.0::Double) <interactive>:30:17: Couldn't match expected type `Integer' with actual type `Double' In the second argument of `(+)', namely `(1.0 :: Double)' ... Thanks for enlightening me. -M

On Fri, Dec 13, 2013 at 8:57 AM, Mark Fredrickson < mark.m.fredrickson@gmail.com> wrote:
On Fri, Dec 13, 2013 at 8:59 AM, Antonio Nikishaev
wrote: The previous exchange prompted me to whip up a Num instance for lists:
instance Num a => Num [a] where negate = fmap negate (+) = zipWith (+) (*) = zipWith (+) fromInteger x = [fromInteger x] abs = fmap abs signum = fmap signum
It mostly behaves how one would expect:
let a = [1,2,3] ghci> let b = [4,5,6,7] ghci> a + b [5,7,9] ghci> 1 + a [2]
I was wondering whey `1 + a` succeeds. At first I thought it could be the `fromInteger` definition, but this explanation were true, I should be able to add integers and doubles freely, which I can't:
ghci> fromInteger (1::Integer) + (1.0::Double) 2.0 ghci> (1::Integer) + (1.0::Double)
<interactive>:30:17: Couldn't match expected type `Integer' with actual type `Double' In the second argument of `(+)', namely `(1.0 :: Double)' ...
Thanks for enlightening me.
`1 + a` works for the same reason `1 + (1.0::Double)` works: type inference. `1 + a` in this instance is equivalent to `(1 :: Num [Integer]) + a` which should compile down to something equivalent to `fromInteger 1 + a`. -bob

I guess you meant (*) = zipWith (*) ? Dumb question: would it be fine to use such an instance in real world application code (in contrast with library code... I guess it would be frowned upon there?) are there any "dangers"... weird interactions? -- xmpp: berdario@gmail.com bitmessage: BM-2cTYXfGiSTsnx3righ6aHcJSWe4MV17jDP gpg fingerprint: 3F8D53518012716C4EEF7DF67B498306B3BF75A0 (used just for signing commits)

When using this hack, I prefer `fromInteger x = repeat (fromInteger x)`.
That way, you get
> 2 * [1,2,3]
[2,4,6]
It's cute for playing around, but the Num instance for lists is somewhat
discouraged in "real" code.
-- Dan Burton
On Fri, Dec 13, 2013 at 10:15 AM, Dario Bertini
I guess you meant
(*) = zipWith (*) ?
Dumb question: would it be fine to use such an instance in real world application code (in contrast with library code... I guess it would be frowned upon there?)
are there any "dangers"... weird interactions?
-- xmpp: berdario@gmail.com bitmessage: BM-2cTYXfGiSTsnx3righ6aHcJSWe4MV17jDP gpg fingerprint: 3F8D53518012716C4EEF7DF67B498306B3BF75A0 (used just for signing commits) _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Fri, Dec 13, 2013 at 5:57 PM, Mark Fredrickson
On Fri, Dec 13, 2013 at 8:59 AM, Antonio Nikishaev
wrote: The previous exchange prompted me to whip up a Num instance for lists:
instance Num a => Num [a] where negate = fmap negate (+) = zipWith (+) (*) = zipWith (+) fromInteger x = [fromInteger x] abs = fmap abs signum = fmap signum
Wouldn't it make more sense to have fromInteger be `repeat . fromInteger`? This would make it an instance for ZipList, not list. You could even give a general instance for applicatives: instance (Num a, Applicative f) => Num (f a) where negate = fmap negate (+) = liftA2 (+) (*) = liftA2 (*) fromInteger = pure . fromInteger abs = fmap abs signum = fmap signum For ZipList this behaves like your instance, except fromInteger produces an infinite list like 'repeat . fromInteger'. The list instance instead computes all possiblities: ghci> [1,2,3] + [4,5,6,7] [5,6,7,8,6,7,8,9,7,8,9,10] Erik

Wouldn't it make more sense to have fromInteger be `repeat . fromInteger`? This would make it an instance for ZipList, not list. You could even give a general instance for applicatives:
Very neat. I had tried using the standard Applicative instance for lists, as I wasn't aware of the ZipList newtype. Very useful. On the question of whether any of this is a good idea, I found this discussion that mostly dismissed it based on the handling of literals (which if I understand it, is the source of my original question): http://www.haskell.org/pipermail/libraries/2012-October/018663.html At the end Conal Elliot points to the applicative-numbers package that has a nearly verbatim implementation of Num (f a). -M
participants (5)
-
Bob Ippolito
-
Dan Burton
-
Dario Bertini
-
Erik Hesselink
-
Mark Fredrickson