3

my question is in reference to this post, specifically:

data Actions a = Actions {
    actEval :: a,
    actMap  :: (a -> a) -> Actions a }

I am confused by the recursive defintion of actMap function in that it returns a reference to Actions, recursively, ie what is the base case for recursion, since there's no type specified for a?

How would Actions structure be represented in Common Lisp??

EDIT: Also, Actions constructor takes 2 arguments (as mentioned in the original post). Then what is Actions a, as returned by the actMap??

Community
  • 1
  • 1
  • what do you mean by "since there's no type specified for `a`"? Haskell is lazily evaluated so you can have recursive structures with no "base case", like `data Infinite = Next Infinte` – jberryman Dec 13 '12 at 19:32
  • 2
    You seem to be confusing type declarations with data of that type, which makes it hard to tell what your intended question is. – C. A. McCann Dec 13 '12 at 19:46

3 Answers3

1

First of all don't confuse type constructor with data constructor.

data Actions a = ..

here Actions is a type constructor. It takes a type a and gives a type Actions a whereas

data Actions a = Actions ..

The second Actions is a data constructor. So to construct a value of type Actions a you need to use data constructor Actions with two values, one of type a and other of type (a -> a) -> Actions a.

The definition of Actions is recursive in terms of type, it doesn't mean you need to have a base case for it. You can construct a value of the above type as

construct :: a -> Actions a
construct v = Actions v (\fn -> construct $ fn v)

It is a valid construction as the first value to the data constructor is of type a and the other is a function of the above specified type.

Satvik
  • 11,238
  • 1
  • 38
  • 46
  • how would Actions be represented in lisp??? Something like this ??? (defun actEval (a) a) (defun actMap (f a) '(f (Actions a))) (defun Actions (arg1 arg2) (list((actEval arg1) (actMap arg2 arg1))) ) – M.Savchenko Dec 13 '12 at 20:36
  • @M.Savchenko I don't know lisp so I can not tell. – Satvik Dec 14 '12 at 04:25
0

Well, in Lisp it can be represented just as a structure:

(defstruct act eval map)

And to follow-up on the mentioned post, you would use it somewhat like this:

(defun mk-lit (x)
  (make-act :eval x
            :map (lambda (f) (mk-lit (funcall f x)))))

(defun mk-sum (x y)
  (make-act :eval (+ (act-eval x) (act-eval y))
            :map (lambda (f)
                   (mk-sum (funcall (act-map x) f)
                           (funcall (act-map y) f)))))

CL-USER> (mk-sum (mk-lit 1) (mk-lit 2))
#S(ACT :EVAL 3 :MAP #<CLOSURE (LAMBDA # :IN MK-SUM) {100471902B}>)

CL-USER> (funcall (act-map (mk-sum (mk-lit 1) (mk-lit 2)))
                  #'print)
1 
2 
#S(ACT :EVAL 3 :MAP #<CLOSURE (LAMBDA # :IN MK-SUM) {1007E476FB}>)

EDIT: But it's definitely not the most optimal way to deal with such problem in Lisp - there're much simpler and powerful approaches.

Vsevolod Dyomkin
  • 9,343
  • 2
  • 31
  • 36
0

As @Satvik mentioned, don't confuse the data type with its constructor. The definition could be changed to

data Actions a = ActionsConstructor {
    actEval :: a,
    actMap  :: (a -> a) -> Actions a }

which makes a better distinction between the two concepts.

This is a standard recursive data type. This is quite similar to lists, for example:

data List a = Nil | Cons { head :: a, tail :: List a }

only in the case of Actions, the structure is potentially infinite - you can always pass another function to actMap to get another action, while a list can be terminated by Nil at some place.

Petr
  • 62,528
  • 13
  • 153
  • 317