Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will call to fmap be removed when newtype is a Functor?

Tags:

haskell

If I create a newtype:

newtype Bloo a = Bloo a 

And make it a Functor

instance Functor Bloo where
    fmap f (Bloo a) = Bloo $ f a

Will

fmap f (Bloo a)

be converted to

f a

in the compiled program?

like image 842
bwroga Avatar asked Jun 21 '21 14:06

bwroga


People also ask

What is functor in Haskell?

Functor in Haskell is a kind of functional representation of different Types which can be mapped over. It is a high level concept of implementing polymorphism. According to Haskell developers, all the Types such as List, Map, Tree, etc. are the instance of the Haskell Functor.

Why is functor useful?

Functor is also important in its role as a superclass of Applicative and of Traversable . When working with these more powerful abstractions, it's often very useful to reach for the fmap method. Show activity on this post. For example, it's possible to derive the function lift in a way that works for any functor.

Is maybe a functor Haskell?

Another simple example of a functor is the Maybe type. This object can contain a value of a particular type as Just , or it is Nothing (like a null value).

Is string a functor Haskell?

String is not a functor, because it has the wrong kind.

What happens when you FMAP a functor?

The mapping operation by itself does not modify the values in the functor, only the function. The structure of the functor remains unchanged and only the values are modified. fmap returns an identical functor as the original, with its values swapped to the result of calling a given function with the original value as an argument.

How do you use FMAP with two functions?

fmap (f . g) == fmap f . fmap g If two sequential mapping operations are performed one after the other using two functions, the result should be the same as a single mapping operation with one function that is equivalent to applying the first function to the result of the second.

What are the laws of functor mapping?

Functors are required to obey certain laws in regards to their mapping. Ensuring instances of Functor obey these laws means the behaviour of fmap remains predictable. When performing the mapping operation, if the values in the functor are mapped to themselves, the result will be an unmodified functor. fmap (f . g) == fmap f . fmap g

What is the const functor in C++ FMAP?

The C++ implementation of fmap also ignores the function argument and essentially re-casts the Const argument without changing its value: template<class C, class A, class B> Const<C, B> fmap (std::function<B (A)> f, Const<C, A> c) { return Const<C, B> {c._v}; } Despite its weirdness, the Const functor plays an important role in many constructions.


Video Answer


1 Answers

Almost certainly, yes, but it does require fmap to be inlined, which may not happen under certain circumstances. For example if it is deemed to large (not really relevant in this case) or if you annotate it with a {-# NOINLINE fmap #-} annotation. In those cases it will just be a function that applies f to its argument, like: fmap f x = f x.

You can try it out for yourself. Take this code for example:

-- Test.hs
newtype Test a = Test a
  deriving Show

instance Functor Test where
  fmap f (Test x) = Test (f x)

main = print $ fmap (+ 1) (Test 1)

And compile it with ghc Test.hs -ddump-simpl -dsuppress-all -fforce-recomp. That will output a bunch of stuff, but somewhere you will find the main function:


-- RHS size: {terms: 8, types: 9, coercions: 3, joins: 0/0}
main
  = $ (print ($fShowTest $fShowInteger))
      ((+ $fNumInteger 1 1) `cast` <Co:3>)

If you squint a bit, you might see that the fmap is gone and it is simply summing 1 and 1.

If you enable optimizations with -O1 then it will even evaluate that 1 + 1 at compile time:

-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
main3 = 2

-- RHS size: {terms: 9, types: 11, coercions: 0, joins: 0/0}
main2
  = case $w$cshowsPrec4 11# main3 [] of { (# ww3_a2vc, ww4_a2vd #) ->
    : ww3_a2vc ww4_a2vd
    }

-- RHS size: {terms: 3, types: 1, coercions: 0, joins: 0/0}
main1 = ++ $fShowTest2 main2

-- RHS size: {terms: 4, types: 0, coercions: 0, joins: 0/0}
main = hPutStr' stdout main1 True

This output is a bit more obscure, but I hope you can recognize main3 = 2 which is the result of 1 + 1.

If you add a {-# NOINLINE fmap #-} pragma (and disable optimizations again) you will get:

-- RHS size: {terms: 13, types: 13, coercions: 3, joins: 0/1}
main
  = $ (print ($fShowTest $fShowInteger))
      ($cfmap1_r1CZ
         (let { ds_d1Cs = 1 } in
          \ ds1_d1Cr -> + $fNumInteger ds1_d1Cr ds_d1Cs)
         (1 `cast` <Co:3>))

Which is also complicated, but you might recognize $cfmap1_r1CZ which is a name-mangled version of the fmap function.

like image 131
Noughtmare Avatar answered Nov 15 '22 08:11

Noughtmare