What's a shorter way of writing `(\ x -> traceShow x x )`? - debugging

Printing the value of an expression is a common practice in debugging. For example, if I have a piece of code like this
my . super . cool . fUnCtIoN . chain $ value
and I am trying to see the output of fUnCtIoN . chain, I would add
my . super . cool . (\ x -> traceShow x x ) . fUnCtIoN . chain $ value
which is mouthful for a simple task like this, not to mention if I want to print many intermediate results:
(\ x -> traceShow x x )
. my
. (\ x -> traceShow x x )
. super
. (\ x -> traceShow x x )
. cool
. (\ x -> traceShow x x )
. fUnCtIoN
. (\ x -> traceShow x x )
. chain
$ value
It would just look awful. Is there a better way to do this?

Just use traceShowId! It does exactly what you're asking for.
my . super . cool . traceShowId . fUnCtIoN . chain $ value

Yes. join traceShow.
λ> import Control.Monad
λ> :t join
join :: Monad m => m (m a) -> m a
λ> :t join (+)
join (+) :: Num a => a -> a
In the case of the function monad, join f x = f x x, so join traceShow is equivalent to \x -> traceShow x x.
Or make a where clause that provides a new definition of (.):
--...your code without the nasty bits...
where
(.) f g a = f ( join traceShow (g a))
Which may just help, though there will be one more traceShow call than previously.

How about a helper function for adding a trace call to a function:
dbg :: Show a => String -> a -> a
dbg name x = trace (name ++ ": " ++ show x) x
main = do
let x = dbg "my" . my
. dbg "super" . super
. dbg "cool" . cool
. dbg "func" . fUnCtIoN
. dbg "chain" . chain
$ value
print x
my = (+1)
super = (+2)
cool = (+3)
fUnCtIoN = (+4)
chain = (+5)
value = 3
Output:
chain: 3
func: 8
cool: 12
super: 15
my: 17
18

You could write a higher-order function which takes a function of two arguments and uses the same value for both arguments.
applyBoth :: (a -> a -> b) -> a -> b
applyBoth f x = f x x
(Aside: this is join for the "reader" monad (->) a.)
Then you can use that combinator in curried form:
applyBoth traceShow
. my
. applyBoth traceShow
. super
. applyBoth traceShow
. cool
. applyBoth traceShow
. fUnCtIoN
. applyBoth traceShow
. chain
$ value
Or define an alias for applyBoth traceShow.
traceS = applyBoth traceShow
traceS
. my
. traceS
. super
. traceS
. cool
. traceS
. fUnCtIoN
. traceS
. chain
$ value
For maximum terseness points, you can automatically interleave traceS into a list of functions by folding it up:
showSteps :: Show a => [a -> a] -> a -> a
showSteps = foldr (\f g -> f . traceS . g) id
showSteps [my, super, cool, fUnCtIoN, chain] value
Edit Eh, what the hell... It's not entirely relevant, but here's how to make showSteps work when you want to pipeline your data through a number of types. It's an example of a program we wouldn't be able to write without GHC's advanced type system features (GADTs and RankNTypes in this instance).
Path is a GADT which explains how to walk through a directed graph of types, starting at the source type x and ending at the destination type y. It's parameterised by a category c :: * -> * -> *.
infixr 6 :->
data Path c x y where
End :: Path c z z
(:->) :: c x y -> Path c y z -> Path c x z
:-> reminds us that a journey of a thousand miles begins with a single step: if the category you're working in lets you go from x to y, and you can take a path from y to z, you can go from x to z.
End is for when you have reached your destination - it's pretty easy to walk from z to z by not walking at all.
So Path has the same recursive structure as a linked list, but with a more flexible approach to the things inside it. Rather than requiring all of its elements to have the same type, it gives you a way to join up arrows like dominos, as long as the return type of one arrow matches the input type of the next. (To use the mathematical jargon: if you view the underlying category c as a logical relation, then End augments c with reflexivity and :-> augments c with transitivity. Path c thus constructs the reflexive transitive closure of c. Another way of looking at this is that Path is the free category, much like [] is the free monoid; you can define instance Category (Path c) without any constraint on c.)
You can fold up a Path with exactly the same code as you use to fold up a list, but the type is more precise: the folding function can't know anything a priori about the types of the arrows inside the path.
foldr :: (forall x y. c x y -> r y z -> r x z) -> r z z -> Path c x z -> r x z
foldr f z End = z
foldr f z (x :-> xs) = f x $ foldr f z xs
At this point, I could define type-aligned sequences of functions (type TAS = Path (->)) and show you how f :-> g :-> h :-> End can be folded up into h . g . f, but since our goal is to print out all the intermediate values, we have to use a category with a tiny bit more structure than plain old ->. (Thanks to #dfeuer in the comments for the suggestion - I've adjusted the name he gave to better reflect the attention-seeking nature of my behaviour.)
data Showoff x y where
Showoff :: Show y => (x -> y) -> Showoff x y
Showoff is just like a regular function, except it assures you that the return value y will be Showable. We can use this extra bit of knowledge to write showSteps for paths in which each step is a Showoff.
type ShowTAS = Path Showoff
showSteps :: ShowTAS a b -> a -> b
showSteps path = foldr combine id path . traceS
where combine (Showoff f) g = g . traceS . f
It strikes me as a bit of a shame to use the impure traceS right in the midst of all this strongly typed fun. In real life I'd probably return a String along with the answer.
To prove that it does actually work, here is a chain of functions with varying types. We take in a String, read it into an Int, add one to it, convert it to a Float, then divide it by 2.
chain :: ShowTAS String Float
chain = Showoff read :-> plusOne :-> toFloat :-> divideTwo :-> End
where plusOne :: Showoff Int Int
plusOne = Showoff (+1)
toFloat :: Showoff Int Float
toFloat = Showoff fromIntegral
divideTwo :: Showoff Float Float
divideTwo = Showoff (/2)
ghci> showSteps chain "4"
"4"
4
5
5.0
2.5
2.5 -- this last one is not from a traceShow call, it's just ghci printing the result
Fun!

Related

OCaml syntax: variables side-by-side

I feel like I'm missing some important fundamentals regarding this weird language.
Consider the following program:
let q f x = f x x;;
let s = q (+);;
If I run this in OCaml, I get:
val q : ('a -> 'a -> 'b) -> 'a -> 'b = <fun>
val s : int -> int = <fun>
Compared to other OCaml code I've seen, the syntax for this is really weird to me. In the first line, what does setting q to f x x do? What does q (+) do as well (hoping I can understand this if I get the first part)? Any help understanding this code would help.
You are probably missing the fact that a space is application of the function.
With parentheses for arguments what you have is
q(f,x) = f(x,x)
s(n) = q(plus, n)
plus(k,l) = k + l
(+) being a shortcut for the function which takes x and y and returns x + y, which you can write (+) x x as well.
In your case q (+) is the function
fun x -> x + x

Performance of Foldable's default methods

I've been exploring the Foldable class and also the the Monoid class.
Firstly, lets say I want to fold over a list of the Monoid First. Like so:
x :: [First a]
fold? mappend mempty x
Then I assume in this case the most appropriate fold would be foldr, as mappend for First is lazy in it's second argument.
Conversely, for Last we'd want to foldl' (or just foldl I'm not sure).
Now moving away from lists, I've defined a simple binary tree like so:
{-# LANGUAGE GADTs #-}
data BinaryTree a where
BinaryTree :: BinaryTree a -> BinaryTree a -> BinaryTree a
Leaf :: a -> BinaryTree a
And I've made it Foldable with the most straightforward definition:
instance Foldable BinaryTree where
foldMap f (BinaryTree left right) =
(foldMap f left) `mappend` (foldMap f right)
foldMap f (Leaf x) = f x
As Foldable defines fold as simply foldMap id we can now do:
x1 :: BinaryTree (First a)
fold x1
x2 :: BinaryTree (Last a)
fold x2
Assuming our BinaryTree is balanced, and there's not many Nothing values, these operations should take O(log(n)) time I believe.
But Foldable also defines a whole lot of default methods like foldl, foldl', foldr and foldr' based on foldMap.
These default definitions seem to be implemented by composing a bunch of functions, wrapped in a Monoid called Endo, one for each element in the collection, and then composing them all.
For the purpose of this discussion I am not modifying these default definitions.
So lets now consider:
x1 :: BinaryTree (First a)
foldr mappend mempty x1
x2 :: BinaryTree (Last a)
foldl mappend mempty x2
Does running these retain O(log(n)) performance of the ordinary fold? (I'm not worried about constant factors for the moment). Does laziness result in the tree not needing to be fully traversed? Or will the default definitions of foldl and foldr require an entire traversal of the tree?
I tried to go though the algorithm step by step (much like they did on the Foldr Foldl Foldl' article) but I ended up completely confusing myself as this is a bit more complex as it involves an interaction between Foldable, Monoid and Endo.
So what I'm looking for is an explanation of why (or why not) the default definition of say foldr, would only take O(log(n)) time on a balanced binary tree like above. A step by step example like what's from the Foldr Foldl Foldl' article would be really helpful, but I understand if that's too difficult, as I totally confused myself attempting it.
Yes, it has O(log(n)) best case performance.
Endo is a wrapper around (a -> a) kind of functions that:
instance Monoid (Endo a) where
mempty = Endo id
Endo f `mappend` Endo g = Endo (f . g)
And the default implementation of foldr in Data.Foldable:
foldr :: (a -> b -> b) -> b -> t a -> b
foldr f z t = appEndo (foldMap (Endo #. f) t) z
The definition of . (function composition) in case:
(.) f g = \x -> f (g x)
Endo is defined by newtype constructor, so it only exists at compile stage, not run-time.
#. operator changes the type of it's second operand and discard the first.
The newtype constructor and #. operator guarantee that you can ignore the wrapper when considering performance issues.
So the default implementation of foldr can be reduced to:
-- mappend = (.), mempty = id from instance Monoid (Endo a)
foldr :: (a -> b -> b) -> b -> t a -> b
foldr f z t = foldMap f t z
For your Foldable BinaryTree:
foldr f z t
= foldMap f t z
= case t of
Leaf a -> f a z
-- what we care
BinaryTree l r -> ((foldMap f l) . (foldMap f r)) z
The default lazy evaluation in Haskell is ultimately simple, there are just two rules:
function application first
evaluate the arguments from left to right if the values matter
That makes it easy to trace the evaluation of the last line of the code above:
((foldMap f l) . (foldMap f r)) z
= (\z -> foldMap f l (foldMap f r z)) z
= foldMap f l (foldMap f r z)
-- let z' = foldMap f r z
= foldMap f l z' -- height 1
-- if the branch l is still not a Leaf node
= ((foldMap f ll) . (foldMap f lr)) z'
= (\z -> foldMap f ll (foldMap f lr)) z'
= foldMap f ll (foldMap f lr z')
-- let z'' = foldMap f lr z'
= foldMap f ll z'' -- height 2
The right branch of the tree is never expanded before the left has been fully expanded, and it goes one level higher after an O(1) operation of function expansion and application, therefore when it reached the left-most Leaf node:
= foldMap f leaf#(Leaf a) z'heightOfLeftMostLeaf
= f a z'heightOfLeftMostLeaf
Then f looks at the value a and decides to ignore its second argument (like what mappend will do to First values), the evaluation short-circuits, results O(height of the left-most leaf), or O(log(n)) performance when the tree is balanced.
foldl is all the same, it's just foldr with mappend flipped i.e. O(log(n)) best case performance with Last.
foldl' and foldr' are different.
foldl' :: (b -> a -> b) -> b -> t a -> b
foldl' f z0 xs = foldr f' id xs z0
where f' x k z = k $! f z x
At every step of reduction, the argument is evaluated first and then the function application, the tree will be traversed i.e. O(n) best case performance.

Is it possible to infer the normalized source of a pure λ function on Haskell?

Let a pure λ function be a term with nothing but abstractions and applications. On JavaScript, it is possible to infer the source code of a pure function by applying all abstractions to variadic functions that collect their argument list. That is, this is possible:
lambdaSource(function(x){return x(x)}) == "λx.(x x)"
See the code for lambdaSource on this gist. That function became particularly useful for my interests since it allows me to use existing JS engines to normalize untyped lambda calculus expressions much faster than any naive evaluator I could code by myself. Moreover, I know λ-calculus functions can be expressed in Haskell with help of unsafeCoerce:
(let (#) = unsafeCoerce in (\ f x -> (f # (f # (f # x)))))
I do not know how to implement lambdaSource in Haskell because of the lack of variadic functions. Is it possible to infer the normalized source of a pure λ function on Haskell, such that:
lambdaSource (\ f x -> f # (f # (f # x))) == "λ f x . f (f (f x))"
?
Yes, you can, but you need to provide the spine of the type of your function, so it doesn't work for ULC. See also the whole lecture notes.
But as Daniel Wagner says you can just use HOAS.
There is also another opportunity: here is something that looks like HOAS, but is FOAS actually, and all you need is suitable normalization by evaluation (in terms of quote, in terms of reify & reflect). pigworker also wrote a Haskell version of the Jigger, but I can't find it.
We can also do this type-safely in type theory: one way is to use liftable terms (which requires a postulate), or we can reify lambda terms into their PHOAS representation and then convert PHOAS to FOAS (which is very complicated).
EDIT
Here is some HOAS-related code:
{-# LANGUAGE GADTs, FlexibleInstances #-}
infixl 5 #
data Term a = Pure a | Lam (Term a -> Term a) | App (Term a) (Term a)
(#) :: Term a -> Term a -> Term a
Lam f # x = f x
f # x = App f x
instance Show (Term String) where
show = go names where
names = map (:[]) ['a'..'z'] ++ map (++ ['\'']) names
go :: [String] -> Term String -> String
go ns (Pure n) = n
go (n:ns) (Lam f) = concat ["\\", n, " -> ", go ns (f (Pure n))]
go ns (App f x) = concat [go ns f, "(", go ns x, ")"]
k :: Term a
k = Lam $ \x -> Lam $ \y -> x
s :: Term a
s = Lam $ \f -> Lam $ \g -> Lam $ \x -> f # x # (g # x)
omega :: Term a
omega = (Lam $ \f -> f # f) # (Lam $ \f -> f # f)
run t = t :: Term String
main = do
print $ run $ s -- \a -> \b -> \c -> a(c)(b(c))
print $ run $ s # k # k -- \a -> a
-- print $ run $ omega -- bad idea
Also, instead of writing this Lams, #s and stuff, you can parse string representations of lambda terms to HOAS — that's not harder than printing HOAS terms.

Haskell any way to improve this code

Hey I have implemented this code segment as a move ordering system for a alpha-beta pruning function. It does speed up my code by a little but when I profiled my code I saw it was very clunky.
move_ord [] (primary_ord,secondary_ord) = primary_ord ++ secondary_ord
move_ord (y:ys) (primary_ord,secondary_ord) = case no_of_pebbles state y of
0 -> move_ord ys (primary_ord,secondary_ord)
13 -> move_ord ys (y : primary_ord,secondary_ord)
x
| 7 - y == x -> move_ord ys (y : primary_ord,secondary_ord)
| otherwise -> move_ord ys (primary_ord,y : secondary_ord)
It is meant to place moves with specific pebble values (13 and 7-y==x) at the front of the list. While also filtering out illegal moves of 0 pebbles.
Pebbles are stored as Int. y is a Int.
Thank you in advance.
Does the order in which the elements of primary_ord appear matter?
No it does not. I am ordering branches to check first for alpha-beta cutoffs. The cases I outlined have a higher probability of triggering a pruning on the next branch evaluated. Though since I have no other information they can be in any order as long as they appear in front of the other cases.
In that case, you should deliver the good ones as soon as you find them, and only defer delivering the bad ones.
If move_ord is - except in the recursive calls - only called with ([],[]) as the second argument, I'd recommend
move_ord = go []
where
go acc (y:ys) = case no_of_pebbles state y of
0 -> go acc ys
13 -> y : go acc ys
x | x == 7-y -> y : go acc ys
| otherwise -> go (y:acc) ys
go acc _ = acc
Thus a) you can run in smaller space (unless the consumer accumulates the entire result) and b) the consumer need not wait for the entire list to be traversed before it can start working.
Of course, if there are only very few or even none "good" ys, it may not make a difference, and if the consumer needs the entire list before it can do anything neither. But usually, that should improve matters somewhat. Otherwise, there is not much that can be done in this function, no_of_pebbles would be what uses the most resources here.
If move_ord can be called with non-empty primary_ord or secondary_ord, use a wrapper
move_ord xs (primary, secondary) = primary ++ go secondary xs
where
go acc ... -- as above
I'm assuming that move_ord starts out being called as move_ord ys ([], []). We then have a streaming filter pattern on Either.
import Data.Either
sorter :: (a -> Bool) -> [a] -> [Either a a]
sorter p = map go where go x = if p x then Left x else Right x
then,
uncurry (++)
. partitionEithers
. sorter (\x -> no_of_pebbles x == 13 || 7 - x == no_of_pebbles x)
. filter (\x -> no_of_pebbles x != 0)
Which is still a little ugly because we keep computing no_of_pebbles in various places. This might be alright for documentation purposes, but we could also precompute no_of_pebbles.
uncurry (++)
. partitionEithers
. sorter (\(x, num) -> num == 13 || 7 - x == num)
. filter ((!=0) . snd)
. map (\x -> (x, no_of_pebbles x))
Specialization.
As you use literal constant the compiler will infer default Integer type not Int.
Then you need to specialize the type signature of your function, like so.
move_ord :: [Int] -> ([Int], [Int]) -> ([Int], [Int])
Memoization.
Your input list can contain duplicate element, then two strategy are possible.
Memoize your call of no_of_pebbles, it will save you extract computation, or you can sort and remove the duplicate of your input list before processing it.
Return a tuple.
You accumulate the response as a tuple then maybe you should return it as is.
Trying to merge the two element of it into the function seems to be out of scope.
Should be manage later in your code, and it's good to know that list store in tuple are common data type know as dlist.

composing two comparison functions?

I'd like to sort by one property and then by another (if the first property is the same.)
What's the idiomatic way in Haskell of composing two comparison functions, i.e. a function used with sortBy?
Given
f :: Ord a => a -> a -> Ordering
g :: Ord a => a -> a -> Ordering
composing f and g would yield:
h x y = case v of
EQ -> g x y
otherwise -> v
where v = f x y
vitus points out the very cool instance of Monoid for Ordering. If you combine it with the instance instance Monoid b => Monoid (a -> b) it turns out your composition function is just (get ready):
mappend
Check it out:
Prelude Data.Monoid> let f a b = EQ
Prelude Data.Monoid> let g a b = LT
Prelude Data.Monoid> :t f `mappend` g
f `mappend` g :: t -> t1 -> Ordering
Prelude Data.Monoid> (f `mappend` g) undefined undefined
LT
Prelude Data.Monoid> let f a b = GT
Prelude Data.Monoid> (f `mappend` g) undefined undefined
GT
+1 for powerful and simple abstractions
You can use the <> operator. In this example bigSort sorts string by their numerical value, first comparing length and then comparing lexicographically.
import Data.List (sortBy)
import Data.Ord (compare, comparing)
bigSort :: [String] -> [String]
bigSort = sortBy $ (comparing length) <> compare
Example:
bigSort ["31415926535897932384626433832795","1","3","10","3","5"] =
["1","3","3","5","10","31415926535897932384626433832795"]
<> is an alias of mappend from the Data.Monoid module (see jberryman answer).
The (free) book Learn You a Haskell for Great Good! explains how it works here in Chapter 11
instance Monoid Ordering where
mempty = EQ
LT `mappend` _ = LT
EQ `mappend` y = y
GT `mappend` _ = GT
The instance is set up like this: when we mappend two Ordering values, the one on the left is kept, unless the value on the left is EQ, in which case the right one is the result. The identity is EQ.

Resources