basic Functor, Applicative and Monad instances

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

basic Functor, Applicative and Monad instances

Imants Cekusins
Here are complete working snippets with Functor, Applicative and Monad
instances. This is my first attempt to write own instances rather than
use ready ones.

Here we go:



module Part.Monad where

import Control.Applicative
{-# ANN module ("HLint: ignore Use let"::String) #-}

 {-
   Val' { val = b1 } can also be written as
   Val' b1
 -}


data Val a = Val' {
    val::a
}  deriving Show


data Weather = Cold | Warm deriving Show


instance Functor Val where
-- (a -> b) -> f a -> f b
   fmap ab fa = let  a1 = val fa
                     b1 = ab a1
                in Val' { val = b1 }


instance Applicative Val where
-- a -> f a
   pure a =  Val' { val = a }

-- f (a -> b) -> f a -> f b
   (<*>) fab fa =  let  ab1 = val fab
                        a1 = val fa
                        b1 = ab1 a1
                   in Val' { val = b1 }


instance Monad Val where
-- a -> m a
   return a = Val' { val = a }

--  m a -> (a -> m b) -> m b
   (>>=) ma amb = let a1 = val ma
                 in amb a1


-- pure and return in this example are interchangeable
main::Int -> IO()
main i = do                         -- do:   Val as monad
   v1 <- pure Val' { val = i }      -- pure: applicative

   v2 <- return $ over20 <$> v1     -- <$> : functor
   print v2

   v3 <- return $ Val' weather <*> v2  -- <*> : applicative
   print v3


over20::Int-> Bool
over20 i
   | i > 20 = True
   | otherwise = False


weather::Bool-> Weather
weather False = Cold
weather True = Warm
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: basic Functor, Applicative and Monad instances

Rein Henrichs
This would all be much easier with pattern matching. For example:

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

instance Applicative Val where
  pure = Val
  Val f <*> Val x = Val (f x)

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: basic Functor, Applicative and Monad instances

Imants Cekusins
Cheers, Rein. This is new for me. I tried to make it work.

BTW the monad instance is not used. Commenting it out has no effect on
running main.

How can I apply Val (not IO) Monad instance in this example? Could you
suggest a simple change?
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: basic Functor, Applicative and Monad instances

Imants Cekusins
v2: Val monad is now necessary:

main::Int -> Val Weather
main i = do                         -- do:   Val as monad
   v1 <- return $ Val' i       -- pure: applicative
   v2 <- return $ over20 <$> v1     -- <$> : functor
   v3 <- Val' weather <*> v2  -- <*> : applicative
   return v3
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: basic Functor, Applicative and Monad instances

Imants Cekusins
based on this snippet and Rein's comment, here is monad file template
for intellij Idea to make new monads a quick exercise:

module ${PACKAGE_NAME}.${NAME} where


data ${Type} a = ${ctor} {
    ${prop}::a
}


instance Functor ${Type} where
-- (a -> b) -> f a -> f b
--   fmap f (${ctor} x) = ${ctor} (f x)
   fmap ab fa = let  a1 = ${prop} fa
                     b1 = ab a1
                in fa { ${prop} = b1 }


instance Applicative ${Type} where
-- a -> f a
--  pure = ${ctor}
   pure a =  ${ctor} { ${prop} = a }

-- f (a -> b) -> f a -> f b
--   ${ctor} f <*> ${ctor} x = ${ctor} (f x)
   (<*>) fab fa =  let  ab1 = ${prop} fab
                        a1 = ${prop} fa
                        b1 = ab1 a1
                   in fa { ${prop} = b1 }


instance Monad ${Type} where
-- a -> m a
   return a = ${ctor} { ${prop} = a }

--  m a -> (a -> m b) -> m b
   (>>=) ma amb = let a1 = ${prop} ma
                 in amb a1
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: basic Functor, Applicative and Monad instances

amindfv
You have the types of the functions commented out in the instances. If you use {-# LANGUAGE InstanceSigs #-} you can write them for real (and be sure that they're accurate)

Tom

El Jul 17, 2015, a las 3:53, Imants Cekusins <[hidden email]> escribió:

> based on this snippet and Rein's comment, here is monad file template
> for intellij Idea to make new monads a quick exercise:
>
> module ${PACKAGE_NAME}.${NAME} where
>
>
> data ${Type} a = ${ctor} {
>    ${prop}::a
> }
>
>
> instance Functor ${Type} where
> -- (a -> b) -> f a -> f b
> --   fmap f (${ctor} x) = ${ctor} (f x)
>   fmap ab fa = let  a1 = ${prop} fa
>                     b1 = ab a1
>                in fa { ${prop} = b1 }
>
>
> instance Applicative ${Type} where
> -- a -> f a
> --  pure = ${ctor}
>   pure a =  ${ctor} { ${prop} = a }
>
> -- f (a -> b) -> f a -> f b
> --   ${ctor} f <*> ${ctor} x = ${ctor} (f x)
>   (<*>) fab fa =  let  ab1 = ${prop} fab
>                        a1 = ${prop} fa
>                        b1 = ab1 a1
>                   in fa { ${prop} = b1 }
>
>
> instance Monad ${Type} where
> -- a -> m a
>   return a = ${ctor} { ${prop} = a }
>
> --  m a -> (a -> m b) -> m b
>   (>>=) ma amb = let a1 = ${prop} ma
>                 in amb a1
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: basic Functor, Applicative and Monad instances

amindfv
Right, you'll want to say eg

fmap :: (a -> b) -> Val a -> Val b

Tom


El Jul 17, 2015, a las 12:23, Imants Cekusins <[hidden email]> escribió:

>> InstanceSigs
>
> Thank you Tom.
>
> this sig does not work though:
> fmap ::(a -> b) -> f a -> f b
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Cabal dependencies are per target or global?

Dimitri DeFigueiredo
Hello,

I'm trying to figure out how cabal understands dependencies.

It seems all "build-depends:" sections have to build satisfied for any one
target to be built. Is that correct or is there a problem with my setup?

I assumed those "build-depends:" sections were "per target",
but apparently that not exactly the case.

I have a small .cabal file that builds the second target "myPersonalMain"
if and only if I comment out the build-dependencies for the first target
(i.e. myAgent)

here's my test file agent.cabal:
------------------------------------------------
name:                agent
version:             0.1.0.0
synopsis:            Just testing
author:              Dimitri DeFigueiredo
maintainer:          [hidden email]
build-type:          Simple
cabal-version:       >=1.20

----------------------------------------------
executable myAgent
   main-is:              Main.hs
   hs-source-dirs:       ./src

   build-depends:      base >=4.6 && <4.7
                     , unordered-containers >= 0.2.3.0
                     , unix >= 2.6.0.1
                     , process >= 1.1.0.2
                     , stm >= 2.4.2

   default-language:    Haskell2010

----------------------------------------------
executable myPersonalMain
     main-is:            Mpm.hs
     hs-source-dirs:     ./src
     build-depends:
                   base              >=4.6

     default-language:   Haskell2010
----------------------------------------------

if I try to build the second target I get:

cabal build MyPersonalMain
./agent.cabal has been changed. Re-configuring with most recently used
options. If this fails, please run configure manually.
Resolving dependencies...
Configuring agent-0.1.0.0...
cabal: At least the following dependencies are missing:
process >=1.1.0.2,
stm >=2.4.2,
unix >=2.6.0.1,
unordered-containers >=0.2.3.0

could someone shed some light into this behavior?

Thanks,

Dimitri


_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Cabal dependencies are per target or global?

Dimitri DeFigueiredo

I guess my example was incomplete. I can make GHC run. Here's a modified
version where I do have the ghc-options line. I can build an executable
for the second target (myPersonalMain) by commenting
the "build-depends: section" for the first target (agent).
My .cabal file with (commented lines) is:
------------------------------------------------
name:                agent
version:             0.1.0.0
build-type:          Simple
cabal-version:       >=1.20
------------------------------------------------
executable agent
   main-is:             Main.hs
   hs-source-dirs: ./src

   -- build-depends:      base >=4.6 && <4.7
   --                   , unordered-containers >= 0.2.3.0
   --                   , unix >= 2.6.0.1
   --                   , process >= 1.1.0.2
   --                   , stm >= 2.4.2

   -- Base language which the package is written in.
   default-language:    Haskell2010

----------------------------------------------
executable myPersonalMain
     main-is:            Mpm.hs
     hs-source-dirs:     ./src
     ghc-options:       -main-is Mpm
     build-depends:
                 base              >=4.4

     default-language:   Haskell2010
----------------------------------------------

The contents of Mpm.hs are:

module Mpm where
main = putStrLn "Hi!"

But if I remove the comments in the .cabal file above, I get this:

Dis-machine:cabal-tests dimitri$ cabal build myPersonalMain
./agent.cabal has been changed. Re-configuring with most recently used
options. If this fails, please run configure manually.
Resolving dependencies...
Configuring agent-0.1.0.0...
cabal: At least the following dependencies are missing:
process >=1.1.0.2,
stm >=2.4.2,
unix >=2.6.0.1,
unordered-containers >=0.2.3.0



Is this a bug? Or am I missing something?


Cheers,


Dimitri




On 17/07/15 15:10, Imants Cekusins wrote:
> this could shed some light:
>
> http://stackoverflow.com/questions/14238729/producing-multiple-executables-from-single-project
>
> answer #2 was marked as answered
>
> ghc-options:      -O2 -threaded -with-rtsopts=-N -main-is FirstExecutable

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Cabal dependencies are per target or global?

Karl Voelker-2
On Fri, Jul 17, 2015, at 04:08 PM, Dimitri DeFigueiredo wrote:
> Is this a bug? Or am I missing something?

The dependencies are not global. You can see this by trying to import a
module in Mpm.hs that is in one of the unique dependencies of "agent" -
the import fails. [1]

However, in order to build, you must first configure. And the
"configure" step cannot be done for a single executable - it's done for
the whole package. Since package dependencies are checked during the
configure step, you have to have all the dependencies in place for all
targets.

I think this is probably a good thing, because otherwise, you could end
up installing some packages that satisfy the dependencies of one target,
only to find out that the particular package versions which were chosen
make it impossible to satisfy the dependencies of the other target.

-Karl

1. https://gist.github.com/ktvoelker/d561889ac4bd56cadc2d
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Cabal dependencies are per target or global?

Dimitri DeFigueiredo
Thanks Karl!

The way cabal is working makes sense now.

I don't like it, though. Having a build fail because of changes made to
another target is counter-intuitive to me. I don't understand your
argument for why the current behavior is a good thing. It seems we would
be extending so called "cabal hell" to within targets in a package if we
were to change this? I do wish there were other options here.

Anyway, thanks again for the explanation!


Dimitri

Em 17/07/15 19:29, Karl Voelker escreveu:

> On Fri, Jul 17, 2015, at 04:08 PM, Dimitri DeFigueiredo wrote:
>> Is this a bug? Or am I missing something?
> The dependencies are not global. You can see this by trying to import a
> module in Mpm.hs that is in one of the unique dependencies of "agent" -
> the import fails. [1]
>
> However, in order to build, you must first configure. And the
> "configure" step cannot be done for a single executable - it's done for
> the whole package. Since package dependencies are checked during the
> configure step, you have to have all the dependencies in place for all
> targets.
>
> I think this is probably a good thing, because otherwise, you could end
> up installing some packages that satisfy the dependencies of one target,
> only to find out that the particular package versions which were chosen
> make it impossible to satisfy the dependencies of the other target.
>
> -Karl
>
> 1. https://gist.github.com/ktvoelker/d561889ac4bd56cadc2d
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Cabal dependencies are per target or global?

René Klačan
Hello Dimitri,

I recommend you to use stack (https://github.com/commercialhaskell/stack) instead of cabal. Never had any problem with building since I started using it. It's awesome. It solved all my headaches caused by Cabal. But it still treats dependencies in the same way.

Rene

On Sat, Jul 18, 2015 at 6:47 PM, Dimitri DeFigueiredo <[hidden email]> wrote:
Thanks Karl!

The way cabal is working makes sense now.

I don't like it, though. Having a build fail because of changes made to another target is counter-intuitive to me. I don't understand your argument for why the current behavior is a good thing. It seems we would be extending so called "cabal hell" to within targets in a package if we were to change this? I do wish there were other options here.

Anyway, thanks again for the explanation!


Dimitri

Em 17/07/15 19:29, Karl Voelker escreveu:
On Fri, Jul 17, 2015, at 04:08 PM, Dimitri DeFigueiredo wrote:
Is this a bug? Or am I missing something?
The dependencies are not global. You can see this by trying to import a
module in Mpm.hs that is in one of the unique dependencies of "agent" -
the import fails. [1]

However, in order to build, you must first configure. And the
"configure" step cannot be done for a single executable - it's done for
the whole package. Since package dependencies are checked during the
configure step, you have to have all the dependencies in place for all
targets.

I think this is probably a good thing, because otherwise, you could end
up installing some packages that satisfy the dependencies of one target,
only to find out that the particular package versions which were chosen
make it impossible to satisfy the dependencies of the other target.

-Karl

1. https://gist.github.com/ktvoelker/d561889ac4bd56cadc2d
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners


_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Cabal dependencies are per target or global?

Karl Voelker-2
In reply to this post by Dimitri DeFigueiredo
On Sat, Jul 18, 2015, at 09:47 AM, Dimitri DeFigueiredo wrote:
> I don't like it, though. Having a build fail because of changes made to
> another target is counter-intuitive to me. I don't understand your
> argument for why the current behavior is a good thing. It seems we would
> be extending so called "cabal hell" to within targets in a package if we
> were to change this? I do wish there were other options here.

Yes, that's exactly right - it would be another way to end up in cabal
hell.

There is another option, though: you could put the executables in
separate packages.

-Karl
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners