0

Is there any way I could define a type for an input variable for a lambda function. I've got this as a function

bstar :: Language -> Int -> Language
bstar l n =
    case l of
    [] -> zero
    l -> case n of
            0 -> [[]]
            n -> (\pow l n -> if n == 0 
                              then [[]] 
                              else l `cat` (pow l (n-1))) l n `uni` (bstar l (n-1))

when I compile this in haskell I get mismatch type error 'Int' with 'String'. I was wondering if there's any way I could define the input variable of lambda function "pow" l as a Language. Any Idea?

mehdix_
  • 459
  • 7
  • 19
  • 2
    What are the types of `cat` and `uni`? Defining the type of `l` explicitly might help you localise the type error, but it seems that you actually have a mistake somewhere that you need to correct. – GS - Apologise to Monica Sep 20 '14 at 23:03
  • @GaneshSittampalam CAT and UNI both have type: Language -> Language -> Language. – mehdix_ Sep 20 '14 at 23:05
  • is `Language` a type synonym? What's its definition? – GS - Apologise to Monica Sep 20 '14 at 23:09
  • @GaneshSittampalam Language has this type: type Language = [String] – mehdix_ Sep 20 '14 at 23:11
  • 1
    The function application `(\pow l n -> ...) l n` is passing `l` as `pow`, and `n` as `l`. This looks suspicious. – chi Sep 20 '14 at 23:12
  • 1
    Your code has more significant type errors than just a `Int` / `String` mismatch. The worst one I can see is that the lambda is supposed to take a function as its first argument, but its just getting a `Language` (`l`). Where is the `pow` function supposed to come from? – GS - Apologise to Monica Sep 20 '14 at 23:12
  • Note - your code typechecks for me if I pass `bstar` as the first argument to the lambda, before `l`. But then the whole lambda is rather pointless as you could just replace it with its body, so perhaps you meant to pass something else. – GS - Apologise to Monica Sep 20 '14 at 23:13
  • @GaneshSittampalam Its probably me not fully understanding lambda functions. What I thought is (l) and (n) outside are the parameter I'd send to the lambda function. would you correct me please? – mehdix_ Sep 20 '14 at 23:17
  • They are parameters being sent to the function, but the function takes three arguments - `pow`, `l` and `n`. So you need to pass three things, but you're only passing two things - `l` and `n`. As you've written things, `pow` must be a function itself. What do you actually expect the body of the lambda to calculate? – GS - Apologise to Monica Sep 20 '14 at 23:19
  • My guess is that this code is supposed to take a `Language` (a set of strings, represented as a list), a number `n`, and generate the language of strings which are obtained by concatenating <=n strings from the language. Or, in other words, the union of the k-th powers of the language, with k<=n. – chi Sep 20 '14 at 23:22
  • @GaneshSittampalam That was the mistake then, I supposedly named it pow to call it later in the line hoping to work as recursive on l and (n-1). – mehdix_ Sep 20 '14 at 23:22
  • @GaneshSittampalam Any Idea how would I define it so I can call it recursively? – mehdix_ Sep 20 '14 at 23:23
  • 1
    If you want it to work recusively, define `pow` as a separate function (maybe in a `where`). Or, if you really feel adventurous, use `fix` -- but I think readability would suffer here. – chi Sep 20 '14 at 23:24
  • @GaneshSittampalam Honestly I felt adventurous, I had it working with the pow function defined separately down below. Thanks anyways. – mehdix_ Sep 20 '14 at 23:26
  • If you really want it be inline, you can play with `fix` as @chi suggests, but I agree readability would suffer. Also as well as a `where` clause on the entire function, you could use `let ... in` locally. But I think a `where` is the best option. – GS - Apologise to Monica Sep 20 '14 at 23:28
  • Thinking about it, your attempt is pretty close to being able to use `fix` - just put it before the lambda, as in `fix (\pow ...`. But you should really understand what's going on there before using it. – GS - Apologise to Monica Sep 20 '14 at 23:38
  • @GaneshSittampalam Do I have to include the inner type definition too? was the recursive call of pow correct? – mehdix_ Sep 20 '14 at 23:46
  • I edited my answer with the `fix` solution. – GS - Apologise to Monica Sep 21 '14 at 07:26

2 Answers2

4

You can use the ScopedTypeVariables language extension to enable this syntax:

\(x :: Int) -> x

You enable the extension either with -XScopedTypeVariables on the GHC command-line, or by putting

{-# LANGUAGE ScopedTypeVariables #-}

at the top of the source file.

As I noted in a comment on the question, this may not actually help fix your error. For a lot of straightforward Haskell code including yours, adding a type signature won't actually make the code typecheck when it didn't otherwise. What it will do is make it much easier to locate the type error as it'll become clear to you where your intentions and what the compiler inferred differ.

EDIT following discussion in comments:

The problem with your code is that you're trying to define a recursive function pow with just a lambda, which isn't directly possible. Your lambda expects a function pow as an argument, but you're not passing one.

As @chi's answer and comment notes, your code would probably be cleanest with a where clause instead, but you can also do this with fix if you really want to keep the inline lambda.

It has the following type and definition:

fix :: (a -> a) -> a
fix f = let x = f x in x

In this case, the a type will be the desired type of your pow function, i.e. (Language -> Int -> Language). So fix will end up turning your lambda into a recursive definition - x in the definition of fix corresponds to your pow.

bstar :: Language -> Int -> Language
bstar l n =
    case l of
    [] -> zero
    l -> case n of
            0 -> [[]]
            n -> fix (\pow l n ->
                          if n == 0 
                              then [[]] 
                              else l `cat` (pow l (n-1))) l n `uni` (bstar l (n-1))

You may need to add this at to your imports at the top of the module:

import Data.Function (fix)

You can look at this question for more discussion of fix.

Community
  • 1
  • 1
GS - Apologise to Monica
  • 27,973
  • 10
  • 81
  • 109
  • Thanks, That's what I did right before being adventurous and put it one liner function. Gotta look into Fix anyways. – mehdix_ Sep 20 '14 at 23:29
4

Probably you are looking for something like this:

bstar :: Language -> Int -> Language
bstar l n =
    case l of
    [] -> zero
    l -> case n of
            0 -> [[]]
            n -> pow l n `uni` bstar l (n-1)
   where pow :: Language -> Int -> Language
         pow l n = if n == 0 
                   then [[]] 
                    else l `cat` pow l (n-1)

Let me "restyle" a bit your code, hopefully making it clearer.

bstar :: Language -> Int -> Language
bstar [] _ = zero
bstar _  0 = [[]]
bstar l  n = pow l n `uni` bstar l (n-1)
   where pow :: Language -> Int -> Language
         pow _ 0 = [[]]
         pow l n = l `cat` pow l (n-1)
chi
  • 101,733
  • 3
  • 114
  • 189