Install and configure Automake on OpenBSD

Today, when I tried to compile a project, “make” complained following errors:

# make
CDPATH="${ZSH_VERSION+.}:" && cd . && /bin/sh /root/project/missing aclocal-1.15
/root/project/missing[81]: aclocal-1.15: not found
WARNING: 'aclocal-1.15' is missing on your system.
         You should only need it if you modified 'acinclude.m4' or
         'configure.ac' or m4 files included by 'configure.ac'.
         The 'aclocal' program is part of the GNU Automake package:
         <http://www.gnu.org/software/automake>
         It also requires GNU Autoconf, GNU m4 and Perl in order to run:
         <http://www.gnu.org/software/autoconf>
         <http://www.gnu.org/software/m4/>
         <http://www.perl.org/>
*** Error 127 in /root/project(Makefile:330 './aclocal.m4')

To fix it, first install Automake:

# pkg_add automake
quirks-2.414 signed on 2018-03-28T14:24:37Z
Ambiguous: choose package for automake
a       0: <None>
        1: automake-1.10.3p8
        2: automake-1.11.6p2
        3: automake-1.12.6p1
        4: automake-1.13.4p1
        5: automake-1.14.1p0
        6: automake-1.15.1
        7: automake-1.4.6p5
        8: automake-1.8.5p9
        9: automake-1.9.6p12
Your choice: 6
automake-1.15.1:autoconf-2.69p2: ok
automake-1.15.1: ok

Then “make” prompted it needs “AUTOCONF_VERSION“:

# make
CDPATH="${ZSH_VERSION+.}:" && cd . && /bin/sh /root/project/missing aclocal-1.15
Provide an AUTOCONF_VERSION environment variable, please
aclocal-1.15: error: echo failed with exit status: 127
WARNING: 'aclocal-1.15' is missing on your system.
         You should only need it if you modified 'acinclude.m4' or
         'configure.ac' or m4 files included by 'configure.ac'.
         The 'aclocal' program is part of the GNU Automake package:
         <http://www.gnu.org/software/automake>
         It also requires GNU Autoconf, GNU m4 and Perl in order to run:
         <http://www.gnu.org/software/autoconf>
         <http://www.gnu.org/software/m4/>
         <http://www.perl.org/>
*** Error 127 in /root/project/ (Makefile:330 './aclocal.m4')

Set AUTOCONF_VERSION environment variable:

# export AUTOCONF_VERSION=2.69

Run “autoreconf -f -i“:

# autoreconf -f -i
Provide an AUTOMAKE_VERSION environment variable, please
autoreconf-2.69: aclocal failed with exit status: 127

Set AUTOMAKE_VERSION:

# export AUTOMAKE_VERSION=1.15

This time, it worked:

# autoreconf -f -i
# make
/bin/sh ./config.status --recheck
......

The memo of foldl and foldr in Haskell

foldl and foldr are two functions which make people confused easily. Check the types of them:

foldl :: (b -> a -> b) -> b -> [a] -> b 
foldr :: (a -> b -> b) -> b -> [a] -> b

The common characteristic of them is the result type is the same as accumulator: b. A memo to differentiate them is for foldl: it will traverse the elements from the left of list, and the accumulator also works as the left operand of the binary operator: (b -> a -> b). But for foldr, it goes to the opposite side: it will iterate the elements from the right of list, and the accumulator also works as the right operand of the binary operator: (a -> b -> b).

The other important thing is foldr can operate on infinite list whereas foldl not.

 

Serializing binary data in C++

The following is a simple program to serialize data:

#include <fstream>

int main()
{
        int c = 3;
        std::ofstream f("a.txt");
        f << c;

        return 0;
}

Build and run it on Unix OSs (I test on both OpenBSD and Linux):

# c++ test.cc -o test
# ./test
# hexdump -C a.txt
00000000  33                                                |3|
00000001

We can see the integer 3 is saved in text mode, 0x33, which notates ‘3‘ in ASCII. Change the opening file mode to binary:

std::ofstream f("a.txt", std::ios_base::binary);

You will get the same result. So if you want to dump binary data, you may use write function provided by ostream in C++:

# cat test.cc
#include <fstream>

int main()
{
        int c = 3;
        std::ofstream f("a.txt");
        f.write(reinterpret_cast<char*>(&c), sizeof(c));

        return 0;
}
# c++ test.cc -o test
# ./test
# hexdump -C a.txt
00000000  03 00 00 00                                       |....|
00000004

Similarly, istream‘s read can be used to fetch binary data in serialization.

P.S., the full code is here.

Beware NDEBUG controls assert

According to assert document, if NDEBUG is defined, assert actually does nothing:

#ifdef NDEBUG
#define assert(condition) ((void)0)
#else
#define assert(condition) /*implementation defined*/
#endif

So if your program doesn’t trigger assert as you expected, please check whether NDEBUG is defined or not. E.g., if you use cmake to manage the build process, set CMAKE_BUILD_TYPE‘s value as Release will define NDEBUG:

# cmake -DCMAKE_BUILD_TYPE=Release ..
# make VERBOSE=1
......
/opt/cuda/bin/nvcc ...... \"-Wall\",\"-fPIC\",\"-O3\",\"-DNDEBUG\" ...... 

Warning: don’t put statements in assert, like this:

assert(in >> n);

This will incur the “in >> n” only be executed in debug mode, not release mode.

Differentiate “application operator” and “function composition” in Haskell

I don’t know other guys, but for me, sometimes I am confused with $ (“application operator”) and . (“function composition”) in Haskell, so I want to write a small summary to differentiate them.

Check the type of these two operators:

> :t ($)
($) :: (a -> b) -> a -> b
> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c

For infix operator, $, its left operand should be a function whose type is a->b, the right operand should be the input parameter of this function: a, then get the result b. Check following example:

countWords :: String -> Int
countWords s = length $ words s

words returns a String list which is the input argument of length, then length returns how many words this string has. Run countWords in ghci:

> let countWords s = length $ words s
> countWords "a b c"
3

See . now; maybe another the type notation of . can give you a hand in comprehending it:

(.) :: (b -> c) -> (a -> b) -> (a -> c)

We can think the operands of . are both functions, and the return value is also a function. however, the three functions are not random, but have relationships with their parameters. Modify countWords and run it in ghci:

> let countWords s = length . words s

<interactive>:12:29: error:
    * Couldn't match expected type `a -> [a0]'
                  with actual type `[String]'
    * Possible cause: `words' is applied to too many arguments
      In the second argument of `(.)', namely `words s'
      In the expression: length . words s
      In an equation for `countWords': countWords s = length . words s
    * Relevant bindings include
        countWords :: String -> a -> Int (bound at <interactive>:12:5)

Woops! Error is generated. The reason is the space ” “, or function application has the highest precedence, so words s should be evaluated first:

:t words
words :: String -> [String]

The return value is [String], not a function, so it doesn’t satisfy the type of . who requires the two operands must be functions. Change the countWordsdefinition:

> let countWords s = (length . words) s
> countWords "a b c"
3

This time it works like a charm! For the same reason, the second operand of $ must be consistent with the input parameter of the first operand:

> let countWords = length $ words

<interactive>:18:18: error:
    * No instance for (Foldable ((->) String))
        arising from a use of `length'
    * In the expression: length $ words
      In an equation for `countWords': countWords = length $ words

It is time to warp it up: the operands of . is function, and we can use .to chain many functions to generate a final one which works as the left operand of $, feed it with one argument and produce the final result. Like this:

> length . words $ "1 2 3"
3

The same as:

> length $ words $ "1 2 3"
3