[web-devel] Type-safe URL handling

Michael Snoyman michael at snoyman.com
Fri Mar 26 18:13:13 EDT 2010


On Fri, Mar 26, 2010 at 9:30 AM, Jeremy Shaw <jeremy at n-heptane.com> wrote:

> On Fri, Mar 26, 2010 at 10:30 AM, Michael Snoyman <michael at snoyman.com>wrote:
>
>> Well, given that as a criterion, I agree with the rest of your analysis
>> entirely. However, I think we're looking at the purpose of fromPathSegments
>> very differently. I'm not quite certain I understand why we would want to
>> output the unconsumed segments; if something is unconsumed, then it seems
>> like it's an invalid URL and should fail.
>>
>> In your example, if I request "/Foo/5/6/7", fromPathSegments would return
>> (Right (Foo 5 6), ["7"]); but what is going to consume that 7 now? The use
>> case I envisioned for something like this is:
>>
>> data BlogRoutes = ...
>> data MySite = MyHome | MyBlog BlogRoutes
>> fromPathSegments ("blog":rest) = MyBlog `fmap` fromPathSegments
>>
>>
> But what if you had,
>
> data BlogRoutes = ...
> data Foo = ...
> data MySite = MyHome | MyBlog Foo BlogRoutes
>
> Where the MyBlog constructor has *two* arguments. In theory you want to
> write something like:
>
> fromPathSegments ("MyBlog":rest) = MyBlog `fmap` fromPathSegments ?? `ap`
> fromPathSegments ???
>
> The first fromPathSegments will parse the 'Foo' argument and the second
> fromPathSegments will parse the BlogRoutes argument. To make things more
> interesting, let's assume that Foo and BlogRoutes were defined in 3rd party
> modules that don't even know about each other your app.
>
> The problem is, what arguments do you pass to each fromPathSegments call?
> The first call to fromPathSegments is going to consume some of the path
> segments, and the second call will consume the remaining. But we do not have
> enough information here to know in advance how to split up 'rest' between
> the two calls. Instead we to run the first fromPathSegments and have it tell
> us what part it did not consume.
>
> If what I have said still does not make sense, then try this exercise:
>
> create 3 modules, one each for:
>
> data BlogRoutes = BlogHome
> data Foo = Foo Int | Bar Char Int
> data MySite =  MyBlog Foo BlogRoutes
>
> now create fromPathSegments instances for each of those routes. I think you
> will find that it is difficult to implement the instance for MySite.
> Finally, can you now change the Foo type to:
>
> data Foo = Foo Int Int | Bar Int Char Int
>
> by *only* modifying the Foo module, and without breaking the MySite module?
>
> Regarding the type:
>
> data Foo = Foo Int Int
>
> attempting to parse:
>
> "/Foo/5/6/7"
>
> I think that should be handled in, fromPathInfo :: (PathInfo u) => String
> -> Failing u, when it calls fromPathSegments.
>
> At that point in time we know that all the segments should have been
> consumed... so if there is left over junk, something is wrong.
>
> The latest version of the code is now at:
>
> http://src.seereason.com/web-routes/
>
> I did the renaming but have not made all the other changes yet.
>
> - jeremy
>

Can you give me any real-world examples where you would have URL routes
built up like that? It seems like this is an optimization for the abnormal
case.

Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/web-devel/attachments/20100326/f27e58b8/attachment.html


More information about the web-devel mailing list