quicksort_testing.hs - To use QuickCheck, you need to install it. Techniques beyond what we can cover in an introduction to Haskell. Haskell quicksort” on the web), but it is much more complicated, and requires You can implement an efficient in-place quicksort (search for “efficient Traditional, in-place, quicksort implementation would in a language like Go So this function doesn’t scale to longer lists the way that a more With ++ is relatively slow compared to the usual quicksort partitioning. Partition xs return a copy of the data, whereas quicksort traditionallyĭoes this partitioning in-place without making a copy. ![]() For instance, the list comprehensions that While the source code for quicksort is remarkably short and The listĬomprehension evaluates to a list containing all theĮlements of xs that are less than, or equal to, x. List comprehension, which is a notation inspired by set theory. > quicksort > quicksort "banana" "aaabnn" > quicksort > quicksort, ,, ] ,] in_range :: Int -> Bool in_range x = 0 Bool is_rgb ( r, g, b ) = ( in_range r ) & ( in_range g ) & ( in_range b ) is_gray :: ( Int, Int, Int ) -> Bool is_gray ( r, g, b ) = ( r = g & g = b ) invert_rgb :: ( Int, Int, Int ) -> ( Int, Int, Int ) invert_rgb ( r, g, b ) = ( 255 - r, 255 - g, 255 - b ) - returns the brightness of an RGB triple brightness :: ( Int, Int, Int ) -> Float brightness ( r, g, b ) = (( fromIntegral r ) + ( fromIntegral g ) + ( fromIntegral b )) / 3.0 - returns the distance between two RGB colors dist :: ( Int, Int, Int ) -> ( Int, Int, Int ) -> Float dist ( r1, g1, b1 ) ( r2, b2, g2 ) = let dr = fromIntegral ( r1 - r2 ) dg = fromIntegral ( g1 - g2 ) db = fromIntegral ( b1 - b2 ) in sqrt ( dr ^ 2 + db ^ 2 + dg ^ 2 ) - same as dist, but uses "where" instead of "let/in" dist2 :: ( Int, Int, Int ) -> ( Int, Int, Int ) -> Float dist2 ( r1, g1, b1 ) ( r2, b2, g2 ) = sqrt ( dr ^ 2 + db ^ 2 + dg ^ 2 ) where dr = fromIntegral ( r1 - r2 ) dg = fromIntegral ( g1 - g2 ) db = fromIntegral ( b1 - b2 ) - constraint lo hi x uses guards instead of patterns constrain :: Int -> Int -> Int -> Int constrain lo hi x | x ( Int, Int, Int ) constrain_rgb ( r, g, b ) = ( legal r, legal g, legal b ) where legal = constrain 0 255 - local function defined - thanks to currying - add two RGB colors, constraining any values greater than 255 simple_add :: ( Int, Int, Int ) -> ( Int, Int, Int ) -> ( Int, Int, Int ) simple_add ( r1, g1, b1 ) ( r2, g2, b2 ) = constrain_rgb ( r1 + r2, g1 + g2, b1 + b2 ) - convert a string color name into an RGB triple to_RGB :: String -> ( Int, Int, Int ) to_RGB "red" = ( 255, 0, 0 ) to_RGB "green" = ( 0, 255, 0 ) to_RGB "blue" = ( 0, 0, 255 ) to_RGB "white" = ( 255, 255, 255 ) to_RGB "black" = ( 0, 0, 0 ) to_RGB _ = error "unknown color" - convert an RGB triple into a string name to_Str :: ( Int, Int, Int ) -> String to_Str ( 255, 0, 0 ) = "red" to_Str ( 0, 255, 0 ) = "green" to_Str ( 0, 0, 255 ) = "blue" to_Str ( 255, 255, 255 ) = "white" to_Str ( 0, 0, 0 ) = "black" to_Str _ = error "unknown RGB triple" (And, indeed, one can derive that all order-0 functions are arity-0.- RGB Color Functions - An RGB triple is a 3-tuple (R, G, B), where R, G, and B are integers in the - range [0, 256). and in the world where you allow yourself that flexibility, I think it is perfectly natural to talk about Int as being an order-0, arity-0 function. So, Bool -> Bool has order 1, (a -> b) -> -> has order 2 (and arity 2), ((Int -> r) -> r) -> Cont r Int has order 3. If you allow yourself that flexibility, then you can also talk more flexibly about order, so that the natural generalization of "order" is to count up how many times you can go to the left of an arrow before you are forced to bottom out at a non-arrow type. ![]() ![]() There's no problem with such definitions. The obvious generalization of arity is then to count up how many times you have to go to the right of an arrow before you get to a non-arrow type, so that a -> (b -> c) is arity 2, Bool -> Bool -> Bool -> Bool is arity 3, and Int is arity 0. Despite the fact that the -> type former is binary and so technically a function has one argument and one return type, I think it's nevertheless also useful to have a shorthand for talking and thinking about Haskell that allows you to mentally and verbally chunk a type like a -> (b -> c) as "a function with two arguments". Those beliefs are useful: they form the grounding of a very precise way to talk about Haskell and to understand the behavior of Haskell.īut they've always been a bit too strident for my taste. There is a certain family of beliefs that start with "every function in Haskell has exactly one argument".
0 Comments
Leave a Reply. |