Hi
take 1000 [1..3] still yields [1,2,3] I thought it was supposed to return an error. Any ideas? Thanks, Paul _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
On 9/11/07, PR Stanley <[hidden email]> wrote:
> Hi > take 1000 [1..3] still yields [1,2,3] > I thought it was supposed to return an error. > Any ideas? No, that's the behavior for take specified in the Haskell 98 report: http://haskell.org/onlinereport/standard-prelude.html "-- take n, applied to a list xs, returns the prefix of xs of length n, -- or xs itself if n > length xs." Cheers, Tim -- Tim Chevalier * catamorphism.org * Often in error, never in doubt "Modesty...is both alien and irrelevant to people who are happy in themselves, in their beings, in their skins, their natures, their capacities."--Anne Sayre _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by PR Stanley
On 9/11/07, PR Stanley <[hidden email]> wrote:
Hi If for some reason you want a version that does return an error in that situation, you could do something like the following: take' n _ | (n <= 0) = [] take' n [] | (n > 0) = error "take': list too short" | otherwise = [] take' n (x:xs) = x : take' (n-1) xs I'm not sure why you'd want that, though. The standard implementation gracefully handles all inputs, and usually turns out to be what you want. Really, if I were you, instead of making a version take' as above, I would just use the standard take but check for the length of the list in the places where it matters. -Brent _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by Tim Chevalier
I suppose I'm thinking of head or tail - e.g. head [] or
tail [].
I'm trying to write my own version of the find function. I have a few ideas but not quite sure which would be more suitable in the context of FP. Any advice would be gratefully received - e.g. do I use recursion, list comprehension or what? Thanks, Paul At 00:08 12/09/2007, you wrote: On 9/11/07, PR Stanley <[hidden email]> wrote: _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by Brent Yorgey
byorgey:
> On 9/11/07, PR Stanley <[1][hidden email]> wrote: > > Hi > take 1000 [1..3] still yields [1,2,3] > I thought it was supposed to return an error. > Any ideas? > Thanks, Paul > > If for some reason you want a version that does return an error in that > situation, you could do something like the following: > > take' n _ | (n <= 0) = [] > take' n [] | (n > 0) = error "take': list too short" > | otherwise = [] > take' n (x:xs) = x : take' (n-1) xs And we'd call it unsafeTake, just like unsafeFromJust and unsafeTail :-) -- Don _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
On 9/11/07, Don Stewart <[hidden email]> wrote: byorgey: Hmm, that's funny, I don't recall ever hearing of those functions... =) ooo, Don has a shiny new e-mail address! -Brent _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by Brent Yorgey
On Tue, Sep 11, 2007 at 07:38:18PM -0400, Brent Yorgey wrote:
> On 9/11/07, PR Stanley <[hidden email]> wrote: > > > > Hi > > take 1000 [1..3] still yields [1,2,3] > > I thought it was supposed to return an error. > > Any ideas? > > Thanks, Paul > > > If for some reason you want a version that does return an error in that > situation, you could do something like the following: > > take' n _ | (n <= 0) = [] > take' n [] | (n > 0) = error "take': list too short" > | otherwise = [] > take' n (x:xs) = x : take' (n-1) xs you could also do something like take' n xs = take n (xs ++ error "I want more!") John -- John Meacham - â‘†repetae.netâ‘†johnâ‘ˆ _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by Don Stewart-2
Let me get this right, are you saying it's unsafe when it
returns an error?
Paul At 00:40 12/09/2007, you wrote: byorgey: _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by PR Stanley
prstanley:
> I suppose I'm thinking of head or tail - e.g. head [] or tail []. > I'm trying to write my own version of the find function. I have a few > ideas but not quite sure which would be more suitable in the context of > FP. > Any advice would be gratefully received - e.g. do I use recursion, list > comprehension or what? Well, you want to filter all elements from a list that match a predicate, and then return Just the first match, or Nothing? find :: (a -> Bool) -> [a] -> Maybe a Checking the current behaviour: > find isSpace "haskell is fun" Just ' ' My first go would be something like this: ok, so let's start with 'filter': > filter Char.isSpace "haskell is fun" " " Good, then the natural translation to the Maybe type: > listToMaybe . filter isSpace $ "haskell is fun" Just ' ' And we're almost done. Just firing up QuickCheck: > quickCheck $ \p (xs :: [Int]) -> find p xs == listToMaybe (filter p xs) OK, passed 100 tests. Seems ok. I hope that gives some insight into the process of deriving Haskell implementations by building up a pipeline of pieces. -- Don _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by Brent Yorgey
byorgey:
> On 9/11/07, Don Stewart <[1][hidden email]> wrote: > > byorgey: > > On 9/11/07, PR Stanley <[1]prstanley@[2]ntlworld.com> wrote: > > > > Hi > > take 1000 [1..3] still yields [1,2,3] > > I thought it was supposed to return an error. > > Any ideas? > > Thanks, Paul > > > > If for some reason you want a version that does return an error in > that > > situation, you could do something like the following: > > > > take' n _ | (n <= 0) = [] > > take' n [] | (n > 0) = error "take': list too short" > > | otherwise = [] > > take' n (x:xs) = x : take' (n-1) xs > > And we'd call it unsafeTake, just like unsafeFromJust and unsafeTail :-) > > -- Don > > Hmm, that's funny, I don't recall ever hearing of those functions... =) > > ooo, Don has a shiny new e-mail address! > And a shiny new job in a shiny new city :-) -- Don _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by PR Stanley
prstanley:
> Let me get this right, are you saying it's unsafe when it returns an > error? Partial functions may crash your program, so that's unsafe by some definitions, yep. We have tools that analyse programs for such bugs, in fact (Neil's `catch' program). -- Don _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by Don Stewart-2
On Tue, 2007-09-11 at 16:48 -0700, Don Stewart wrote:
> byorgey: > > On 9/11/07, Don Stewart <[1][hidden email]> wrote: > > > > byorgey: > > > On 9/11/07, PR Stanley <[1]prstanley@[2]ntlworld.com> wrote: > > > > > > Hi > > > take 1000 [1..3] still yields [1,2,3] > > > I thought it was supposed to return an error. > > > Any ideas? > > > Thanks, Paul > > > > > > If for some reason you want a version that does return an error in > > that > > > situation, you could do something like the following: > > > > > > take' n _ | (n <= 0) = [] > > > take' n [] | (n > 0) = error "take': list too short" > > > | otherwise = [] > > > take' n (x:xs) = x : take' (n-1) xs > > > > And we'd call it unsafeTake, just like unsafeFromJust and unsafeTail :-) > > > > -- Don > > > > Hmm, that's funny, I don't recall ever hearing of those functions... =) > > > > ooo, Don has a shiny new e-mail address! > > > > And a shiny new job in a shiny new city :-) In a new country. _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by PR Stanley
> take 1000 [1..3] still yields [1,2,3] You can think about take n as: Take as much as possible, but at most n elements. This behavior has some nice properties as turned out by others, but there are some pitfalls. We have length . take n /= const n in general, instead only length . take n `elem` map const [0..n] holds. Therefore head . length n is unsafe for all n, even strict positive ones. Moreover, it is easy to produce tricky code. Assume you want to know, whether the prefixes of length k are equal and write pref_eq k xs ys = take k xs == take k ys This seems to be a straightforward implementation with good properties. Now play a bit with it: Prelude> pref_eq 3 "ab" "abc" False Prelude> pref_eq 3 "ab" "ab" True Prelude> map (pref_eq 3 "ab") $ Data.List.inits "abc" [False,False,True,False] Uhh, this is not what everybody expects at first glance. In particular, if pref_eq k xs ys == False then *not* necessarily pref_eq k xs (init ys) == False. As always, quickCheck is your friend to assure (or reject) such a property. /BR _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by Brent Yorgey
Hi folks
On 12 Sep 2007, at 00:38, Brent Yorgey wrote: > > On 9/11/07, PR Stanley <[hidden email]> wrote: Hi > take 1000 [1..3] still yields [1,2,3] > I thought it was supposed to return an error. [..] > If for some reason you want a version that does return an error in > that situation, you could do something like the following: > > take' n _ | (n <= 0) = [] > take' n [] | (n > 0) = error "take': list too short" > | otherwise = [] > take' n (x:xs) = x : take' (n-1) xs > > I'm not sure why you'd want that, though. The standard > implementation gracefully handles all inputs, and usually turns out > to be what you want. There are two sides to this form of "grace", though. I'll grant you, it's quite hard to pull off a successful fraud without a degree of aplomb. I always hope that key invariants and hygiene conditions can be built into the static semantics of programs, but where that's impractical somehow, I prefer if the dynamic behaviour makes it as easy as possible to assign the blame for errors. In such circumstances, I'd like operations to complain about bogus input, rather than producing bogus output. These GIGO problems do bite in real life. I spent a long time finding a bug in somebody else's typechecker which boiled down to the silly mistake of zipping the wrong lists together. The right lists were guaranteed to match in length, but there was no reason for the wrong lists to do so. Problem: unless you were doing fairly wacky stuff, they both happened to have length zero. Once weirder things arrived, the discrepancies showed up and the truncations started happening, causing well-formed but ill-typed expressions to be generated by and propagated around the kernel of the system, which eventually choked in some essentially random place. We had many suspects before we found the culprit. If the programmer had used a version of zip which bombed in off-diagonal cases, we'd have been straight there. So I might very well consider having more than one version of take around, depending on my requirements for its use. I might even consider the more informative function which also returns the length of the shortfall. In a dependently typed setting, I wouldn't write take and drop: I'd equip lists with a view incorporating both, guaranteeing the length invariants and that the sublists actually append to the input. But where shame is unattainable, blame is really quite important. All the best Conor _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
Conor McBride wrote:
> Hi folks > > On 12 Sep 2007, at 00:38, Brent Yorgey wrote: > >> >> On 9/11/07, PR Stanley <[hidden email]> wrote: Hi >> take 1000 [1..3] still yields [1,2,3] >> I thought it was supposed to return an error. > > [..] > >> If for some reason you want a version that does return an error in >> that situation, you could do something like the following: >> >> take' n _ | (n <= 0) = [] >> take' n [] | (n > 0) = error "take': list too short" >> | otherwise = [] >> take' n (x:xs) = x : take' (n-1) xs >> >> I'm not sure why you'd want that, though. The standard implementation >> gracefully handles all inputs, and usually turns out to be what you want. > > There are two sides to this form of "grace", though. I'll grant you, it's > quite hard to pull off a successful fraud without a degree of aplomb. > > I always hope that key invariants and hygiene conditions can be built into > the static semantics of programs, but where that's impractical somehow, I > prefer if the dynamic behaviour makes it as easy as possible to assign the > blame for errors. In such circumstances, I'd like operations to complain > about bogus input, rather than producing bogus output. > Then you want a runtime assertion checking error helpful Data.List replacement. Could you use Control.Exception.assert and make a wrapper for Data.List? http://www.haskell.org/ghc/docs/latest/html/users_guide/sec-assertions.html _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by Conor McBride
On Wed, 12 Sep 2007, Conor McBride wrote: > Hi folks > > On 12 Sep 2007, at 00:38, Brent Yorgey wrote: > >> On 9/11/07, PR Stanley <[hidden email]> wrote: Hi >> take 1000 [1..3] still yields [1,2,3] >> I thought it was supposed to return an error. > > [..] > >> If for some reason you want a version that does return an error in that >> situation, you could do something like the following: >> >> take' n _ | (n <= 0) = [] >> take' n [] | (n > 0) = error "take': list too short" >> | otherwise = [] >> take' n (x:xs) = x : take' (n-1) xs >> >> I'm not sure why you'd want that, though. The standard implementation >> gracefully handles all inputs, and usually turns out to be what you want. > > I always hope that key invariants and hygiene conditions can be built into > the static semantics of programs, but where that's impractical somehow, I > prefer if the dynamic behaviour makes it as easy as possible to assign the > blame for errors. In such circumstances, I'd like operations to complain > about bogus input, rather than producing bogus output. Seconded. The List functions have some kind of "scripting language semantics" or "C semantics", that is, consume almost every input, regardless of the meaning of the output, just in order to avoid error messages. Indeed there are some usages like taking a prefix of an infinite list (zip "abc" [1..]), where the current behaviour of 'zip' is useful. However it would be better to have versions of 'zip' to support these special cases. Ideally the equal length could be expressed in types, like zipInfInf :: InfiniteList a -> InfiniteList b -> InfiniteList (a,b) zipInf :: InfiniteList a -> FiniteList n b -> FiniteList n (a,b) zip :: FiniteList n a -> FiniteList n b -> FiniteList n (a,b) , which would need dependent types. > These GIGO problems do bite in real life. I spent a long time finding a bug > in somebody else's typechecker which boiled down to the silly mistake of > zipping the wrong lists together. The right lists were guaranteed to match > in length, but there was no reason for the wrong lists to do so. I had a bug which was due to the wrong order of applications of 'filter' and 'zip'. I had two lists 'a' and 'b' of the same length, where 'b' contained a condition for filtering, then I wrote zip a (filter p b) instead of filter (p . snd) $ zip a b The wrong version was temptingly short, but it matched the wrong elements. The bug had been catched early, if 'zip' would have checked the length of its inputs. _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by haskell-2
Hi
On 12 Sep 2007, at 11:44, ChrisK wrote: > Conor McBride wrote: >> I'd like operations to complain >> about bogus input, rather than producing bogus output. >> > > Then you want a runtime assertion checking error helpful Data.List > replacement. > > Could you use Control.Exception.assert and make a wrapper for > Data.List? > > http://www.haskell.org/ghc/docs/latest/html/users_guide/sec- > assertions.html Hmmm. It might be quite annoying to make it a wrapper if it's just a question of appealing to error rather than returning dummy values in failure cases. Defining the domain of a function can be quite like defining the function itself. Also, sometimes there can be problems arriving at a Bool. For example, zipping colists is a productive coprogram, and it can raise errors in off-diagonal cases, but you can't compute in advance whether you're on the diagonal. A more serious point is that in some cases we might want take to underapproximate, or zip to truncate (or tail [] = [] ?). I don't think there's always a clear "library" choice here. I tend to be pragmatic about it. I was just pointing out that it does sometimes make sense to use less defined functions when one has a more specific domain in mind. I'm usually happy to write the fussy variants myself, if I'm that agitated. Funny old world Conor _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
Hi
> A more serious point is that in some cases we might want take to > underapproximate, or zip to truncate (or tail [] = [] ?). I don't > think there's > always a clear "library" choice here. I have a zipWithEq function I often use, which crashes if the zip'd lists aren't equal. I also have tailSafe which does the tailSafe [] = [] behaviour. I created a hackage package "safe" for the tailSafe function and others, http://www-users.cs.york.ac.uk/~ndm/safe/ . If anyone wants to extend that with deliberately unsafe functions, such as zipWithUnsafe, zipUnsafe, takeUnsafe etc, I'd be happy to accept a patch. If not, I'll probably do it myself at some point in the (potentially distant) future. Thanks Neil _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
In reply to this post by Conor McBride
I quite like the argument that take is a total function and
as such all its return values are from teh specificed range. I can also
see the logic in
take n [] = [] where n > 0 taking n from nothing, or the empty set, returns nothing! The same should apply to head and tail. head or tail of [] should be []. What does the list think? Cheers, Paul At 16:43 12/09/2007, you wrote: Hi _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
Hi
> The same should apply to head and tail. head or tail of [] should be []. > > What does the list think? Disagree, strongly. Its not even possible for head, since [a] -> a. Wadler's theorems for free states that if head is given an empty list the _only_ thing it can do is crash. Thanks Neil _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe |
Free forum by Nabble | Edit this page |