4

I am having a problem defining the following simple text cursor which is represented by a tuple where the first element is a current character and the second one if a function that gets the next one or crashes.

let rec nextAt index text = 
    if index < String.length text then
        (text.[index], (fun() -> nextAt (index + 1) text))
    else
        failwith "End of string."

I am getting

Error   1   Type mismatch. Expecting a
    char * (unit -> 'a)    
but given a
    'a    
The resulting type would be infinite when unifying ''a' and 'char * (unit -> 'a)'
Trident D'Gao
  • 18,973
  • 19
  • 95
  • 159

1 Answers1

4

You'll have to use an intermediate type:

type GetNext = GetNext of (unit -> char * GetNext)

let rec nextAt index text = 
    if index < String.length text then
        (text.[index], GetNext(fun () -> nextAt (index + 1) text))
    else
        failwith "End of string."

The answers to this question about y combinator explore this limitation in greater depth and pose workarounds.

Community
  • 1
  • 1
Daniel
  • 47,404
  • 11
  • 101
  • 179
  • This is a good answer. Of course, if you're going to do this, you might as well add another union case for the end of string scenario instead of throwing an exception (and then look, you've reinvented the lazy list type!). – kvb Dec 02 '13 at 21:38
  • @kvb, are you referring to this: http://msdn.microsoft.com/en-us/library/dd233247.aspx ? – Trident D'Gao Dec 02 '13 at 21:52
  • 1
    @967: He's most likely referring to [the one in PowerPack](http://fsharppowerpack.codeplex.com/SourceControl/latest#libs/head/src/FSharp.PowerPack/LazyList.fsi). – Daniel Dec 02 '13 at 21:58
  • @967 - I meant something along the lines of the PowerPack one, as Daniel surmised. There are some minor differences, though (e.g. PowerPack uses `Lazy<_>` instead of `unit -> _`, so results are cached if they are accessed multiple times). But basically, you can piggy-back on others' work if you'd like to, instead of reimplementing it from scratch. – kvb Dec 03 '13 at 16:29