
Malcolm Wallace
Is there some reason haskell binaries have to be statically linked?
It would not be entirely fair to lay all the blame for large Haskell binaries entirely at the door of static vs. dynamic linking.
Well, considering that compiling the C binary statically linked produces an even bigger executable: $ gcc -static hello.c -o hello_c $ ls -l hello_c hello_hs -rwxrwxr-x 1 jcast jcast 441624 Jul 23 20:56 hello_c -rwxrwxr-x 1 jcast jcast 157028 Jul 18 14:08 hello_hs I think dynamic linking is fair game :)
After all, the Haskell version is dynamically linked against exactly the same shared libraries as the C version, at least on my machine:
ldd Hello (Hello.hs) libm.so.6 => /lib/libm.so.6 (0x40022000) libc.so.6 => /lib/libc.so.6 (0x40044000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
Of course, it is static linking against the *Haskell* runtime system, Prelude and Libraries that is the cause of binary bloat. Quite simply, lots of extra stuff is dragged in that isn't visible in the apparently simple source program. For instance, I can find all the following symbols in the binary for "hello world" (compiled with nhc98):
putStr, shows, showChar, showParen, showString, fromCString, toCString, hGetFileName, hPutChar, hPutStr, error, flip, id, init, length, not, putChar, putStrLn, seq, show, subtract, exitWith, instance Bounded Int (maxBound, minBound), instance Enum Ordering (succ, pred, toEnum, fromEnum, enumFrom, enumFromThen, enumFromTo, enumFromThenTo), instance Enum ErrNo (succ, pred, toEnum, fromEnum, enumFrom, enumFromThen, enumFromTo, enumFromThenTo), instance Monad IO (>>=, >>, return, fail), instance Eq ErrNo (==, /=), instance Eq Int (==, /=), instance Eq Ordering (==, /=), instance Num Int (+, -, *, negate, abs, signum, fromInteger), instance Ord Int (compare, <, <=, >=, >, max, min), instance Show ErrNo (show, showsPrec, showList), instance Show IOError (show, showsPrec, showList), instance Show Int (show, showsPrec, showList)
Well, look at the symbols I find in the statically linked C hello world: _Exit _GLOBAL_OFFSET_TABLE_ _IO_2_1_stderr_ _IO_2_1_stdin_ _IO_2_1_stdout_ _IO_adjust_column _IO_adjust_wcolumn _IO_cleanup _IO_default_doallocate _IO_default_finish _IO_default_imbue _IO_default_pbackfail _IO_default_read _IO_default_seek _IO_default_seekoff _IO_default_seekpos _IO_default_setbuf _IO_default_showmanyc _IO_default_stat _IO_default_sync _IO_default_uflow _IO_default_underflow _IO_default_write _IO_default_xsgetn _IO_default_xsputn _IO_do_write _IO_doallocbuf _IO_fclose _IO_file_attach _IO_file_close _IO_file_close_it _IO_file_doallocate _IO_file_finish _IO_file_fopen _IO_file_init _IO_file_jumps _IO_file_open _IO_file_overflow _IO_file_read _IO_file_seek _IO_file_seekoff _IO_file_setbuf _IO_file_stat _IO_file_sync _IO_file_underflow _IO_file_write _IO_file_xsgetn _IO_file_xsputn _IO_flockfile _IO_flush_all _IO_flush_all_linebuffered _IO_flush_all_lockp _IO_fopen _IO_fprintf _IO_free_backup_area _IO_free_wbackup_area _IO_ftrylockfile _IO_funlockfile _IO_fwide _IO_getdelim _IO_getline _IO_getline_info _IO_helper_jumps _IO_helper_overflow _IO_init _IO_init_marker _IO_init_wmarker _IO_iter_begin _IO_iter_end _IO_iter_file _IO_iter_next _IO_least_marker _IO_least_wmarker _IO_link_in _IO_list_all _IO_list_all_stamp _IO_list_lock _IO_list_resetlock _IO_list_unlock _IO_marker_delta _IO_marker_difference _IO_new_do_write _IO_new_fclose _IO_new_file_attach _IO_new_file_close_it _IO_new_file_finish _IO_new_file_fopen _IO_new_file_init _IO_new_file_overflow _IO_new_file_seekoff _IO_new_file_setbuf _IO_new_file_sync _IO_new_file_underflow _IO_new_file_write _IO_new_file_xsputn _IO_new_fopen _IO_no_init _IO_padn _IO_printf _IO_remove_marker _IO_seekmark _IO_seekoff _IO_seekwmark _IO_setb _IO_sgetn _IO_sputbackc _IO_sputbackwc _IO_sscanf _IO_stderr _IO_stdfile_0_lock _IO_stdfile_1_lock _IO_stdfile_2_lock _IO_stdin _IO_stdin_used _IO_stdout _IO_str_count _IO_str_finish _IO_str_init_readonly _IO_str_init_static _IO_str_jumps _IO_str_overflow _IO_str_pbackfail _IO_str_seekoff _IO_str_underflow _IO_sungetc _IO_sungetwc _IO_switch_to_backup_area _IO_switch_to_get_mode _IO_switch_to_main_get_area _IO_switch_to_main_wget_area _IO_switch_to_wbackup_area _IO_switch_to_wget_mode _IO_un_link _IO_unsave_markers _IO_unsave_wmarkers _IO_vfprintf _IO_vfscanf _IO_vsscanf _IO_wdefault_doallocate _IO_wdefault_finish _IO_wdefault_pbackfail _IO_wdefault_setbuf _IO_wdefault_uflow _IO_wdefault_xsgetn _IO_wdefault_xsputn _IO_wdo_write _IO_wdoallocbuf _IO_wfile_doallocate _IO_wfile_jumps _IO_wfile_overflow _IO_wfile_seekoff _IO_wfile_setbuf _IO_wfile_sync _IO_wfile_underflow _IO_wfile_xsputn _IO_wide_data_0 _IO_wide_data_1 _IO_wide_data_2 _IO_wmarker_delta _IO_wpadn _IO_wsetb __CTOR_END__ __CTOR_LIST__ __DTOR_END__ __DTOR_LIST__ __EH_FRAME_BEGIN__ __FRAME_BEGIN__ __FRAME_BEGIN__ __FRAME_BEGIN__ __FRAME_BEGIN__ __FRAME_BEGIN__ __FRAME_BEGIN__ __FRAME_BEGIN__ __FRAME_BEGIN__ __FRAME_END__ ___brk_addr ___fxstat64 ___xstat64 __access __add_to_environ __addmntent __after_morecore_hook __argz_add_sep __argz_count __argz_create_sep __argz_stringify __atomic_writev_replacement __brk __bss_start __calloc __cfree __clearenv __close __clz_tab __clz_tab __ctype32_b __ctype32_tolower __ctype32_toupper __ctype32_wctrans __ctype32_wctype __ctype32_width __ctype_b __ctype_tolower __ctype_toupper __curbrk __cxa_atexit __data_start __daylight __dcgettext __dcigettext __default_morecore __deregister_frame_info __do_global_ctors_aux __do_global_dtors_aux __dso_handle __elf_set___libc_atexit_element__cleanup__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_free_mem__ __elf_set___libc_subfreeres_element_freeres__ __endmntent __environ __errno_location __evoke_link_warning_llseek __exit_funcs __fcloseall __fcntl __flockfile __fpu_control __free __free_hook __fsetlocking __ftrylockfile __funlockfile __fxstat64 __gconv __gconv_alias_compare __gconv_alias_db __gconv_cache __gconv_close __gconv_close_transform __gconv_compare_alias __gconv_compare_alias_cache __gconv_find_shlib __gconv_find_transform __gconv_get_builtin_trans __gconv_get_path __gconv_load_cache __gconv_lookup_cache __gconv_max_path_elem_len __gconv_modules_db __gconv_open __gconv_path_elem __gconv_path_envvar __gconv_read_conf __gconv_release_cache __gconv_release_shlib __gconv_release_step __gconv_transform_ascii_internal __gconv_transform_internal_ascii __gconv_transform_internal_ucs2 __gconv_transform_internal_ucs2reverse __gconv_transform_internal_ucs4 __gconv_transform_internal_ucs4le __gconv_transform_internal_utf8 __gconv_transform_ucs2_internal __gconv_transform_ucs2reverse_internal __gconv_transform_ucs4_internal __gconv_transform_ucs4le_internal __gconv_transform_utf8_internal __gconv_translit_find __gconv_transliterate __get_avphys_pages __get_nprocs __get_nprocs_conf __get_phys_pages __getclktck __getcwd __getdelim __getdtablesize __getegid __geteuid __getgid __getmntent_r __getpagesize __getpid __getrlimit __gettext_extract_plural __gettext_free_exp __gettext_germanic_plural __gettexterror __gettextlex __gettextparse __getuid __gmon_start__ __guess_grouping __hasmntopt __have_no_fcntl64 __have_no_new_getrlimit __have_no_stat64 __init_misc __ioctl __isatty __isinf __isinfl __isnan __isnanl __kill __libc_argc __libc_argv __libc_calloc __libc_check_standard_fds __libc_close __libc_dlclose __libc_dlopen __libc_dlsym __libc_enable_secure __libc_fatal __libc_fcntl __libc_free __libc_init_first __libc_init_secure __libc_internal_tsd_get __libc_internal_tsd_set __libc_longjmp __libc_lseek __libc_lseek64 __libc_mallinfo __libc_malloc __libc_malloc_initialized __libc_mallopt __libc_memalign __libc_missing_32bit_uids __libc_multiple_libcs __libc_open __libc_open64 __libc_pagesize __libc_pvalloc __libc_read __libc_realloc __libc_setlocale_lock __libc_sigaction __libc_siglongjmp __libc_stack_end __libc_start_main __libc_tsd_DL_ERROR_data __libc_tsd_MALLOC_data __libc_valloc __libc_write __libio_codecvt __libio_translit __llseek __localtime_r __longjmp __lseek __lseek64 __mallinfo __malloc __malloc_check_init __malloc_get_state __malloc_hook __malloc_initialize_hook __malloc_set_state __malloc_stats __malloc_trim __malloc_usable_size __mallopt __mbrlen __mbrtowc __mbsnrtowcs __memalign __memalign_hook __memchr __mempcpy __mktime_internal __mmap __mon_yday __morecore __mpn_add_n __mpn_addmul_1 __mpn_cmp __mpn_construct_double __mpn_construct_float __mpn_construct_long_double __mpn_divrem __mpn_extract_double __mpn_extract_long_double __mpn_impn_mul_n __mpn_impn_mul_n_basecase __mpn_impn_sqr_n __mpn_impn_sqr_n_basecase __mpn_lshift __mpn_mul __mpn_mul_1 __mpn_mul_n __mpn_rshift __mpn_sub_n __mpn_submul_1 __mprotect __mremap __munmap __new_exitfn __new_fclose __new_fopen __new_getrlimit __new_sys_errlist __new_sys_nerr __offtime __open __open64 __overflow __posix_memalign __printf_arginfo_table __printf_fp __printf_fphex __printf_function_table __profil __profile_frequency __progname __progname_full __pthread_atfork __pthread_initialize __pthread_initialize_minimal __pthread_mutex_destroy __pthread_mutex_init __pthread_mutex_lock __pthread_mutex_trylock __pthread_mutex_unlock __pthread_mutexattr_destroy __pthread_mutexattr_init __pthread_mutexattr_settype __pthread_once __pthread_rwlock_rdlock __pthread_rwlock_unlock __pvalloc __rawmemchr __read __readlink __realloc __realloc_hook __register_frame_info __register_printf_function __restore __restore_rt __sbrk __setenv __setfpucw __setitimer __setmntent __sigaction __sigprocmask __start___libc_atexit __start___libc_subfreeres __stop___libc_atexit __stop___libc_subfreeres __stpcpy __strcasecmp __strcasecmp_l __strchrnul __strdup __strerror_r __strncasecmp __strndup __strnlen __strsep __strsep_g __strtod_internal __strtof_internal __strtol_internal __strtold_internal __strtoll_internal __strtoul_internal __strtoull_internal __syscall_error __syscall_error_1 __sysconf __tcgetattr __tdelete __tdestroy __tens __tfind __timezone __tsearch __twalk __tz_convert __tzfile_compute __tzfile_default __tzfile_read __tzname __tzname_cur_max __tzname_max __tzset __tzstring __ubp_memchr __udivdi3 __uflow __umoddi3 __uname __underflow __unsetenv __use_tzfile __valloc __vfscanf __vsscanf __wcrtomb __wcslen __wcsmbs_clone_conv __wcsmbs_gconv_fcts __wcsmbs_last_locale __wcsmbs_load_conv __wcsmbs_named_conv __wcsnlen __wcsrtombs __wmemcpy __wmemmove __wmempcpy __woverflow __write __writev __wuflow __wunderflow __xstat64 _cleanup _dl_all_dirs _dl_argv _dl_aux_init _dl_bind_not _dl_build_local_scope _dl_cache_libcmp _dl_cache_libcmp _dl_catch_error _dl_check_all_versions _dl_check_map_versions _dl_clktck _dl_close _dl_correct_cache_id _dl_debug_bindings _dl_debug_fd _dl_debug_initialize _dl_debug_mask _dl_debug_printf _dl_debug_printf_c _dl_debug_state _dl_debug_vdprintf _dl_do_lookup _dl_do_lookup_versioned _dl_dprintf _dl_dst_count _dl_dst_substitute _dl_dynamic_weak _dl_get_origin _dl_global_scope _dl_global_scope_alloc _dl_hwcap _dl_important_hwcaps _dl_inhibit_rpath _dl_init _dl_init_all_dirs _dl_init_paths _dl_initfirst _dl_initial_searchlist _dl_lazy _dl_load_cache_lookup _dl_load_lock _dl_loaded _dl_lookup_symbol _dl_lookup_symbol_skip _dl_lookup_versioned_symbol _dl_lookup_versioned_symbol_skip _dl_main_searchlist _dl_map_object _dl_map_object_deps _dl_map_object_from_fd _dl_mcount _dl_mcount_wrapper _dl_mcount_wrapper_check _dl_new_object _dl_nloaded _dl_non_dynamic_init _dl_open _dl_origin_path _dl_osversion _dl_out_of_memory _dl_pagesize _dl_platform _dl_platformlen _dl_profile _dl_profile_map _dl_receive_error _dl_reloc_bad_type _dl_relocate_object _dl_rtld_map _dl_runtime_profile _dl_runtime_resolve _dl_setup_hash _dl_signal_cerror _dl_signal_error _dl_start _dl_start_profile _dl_starting_up _dl_sysdep_read_whole_file _dl_unload_cache _dl_verbose _dl_x86_cap_flags _dl_x86_platforms _edata _end _environ _errno _exit _fini _flushlbf _fp_hw _fpioconst_pow10 _i18n_number_rewrite _init _itoa _itoa_base_table _itoa_lower_digits _itoa_upper_digits _itowa _itowa_lower_digits _itowa_upper_digits _libc_intl_domainname _longjmp _longjmp_unwind _new_sys_errlist _new_sys_nerr _nl_C _nl_C_LC_ADDRESS _nl_C_LC_COLLATE _nl_C_LC_CTYPE _nl_C_LC_CTYPE_class _nl_C_LC_CTYPE_class32 _nl_C_LC_CTYPE_class_alnum _nl_C_LC_CTYPE_class_alpha _nl_C_LC_CTYPE_class_blank _nl_C_LC_CTYPE_class_cntrl _nl_C_LC_CTYPE_class_digit _nl_C_LC_CTYPE_class_graph _nl_C_LC_CTYPE_class_lower _nl_C_LC_CTYPE_class_print _nl_C_LC_CTYPE_class_punct _nl_C_LC_CTYPE_class_space _nl_C_LC_CTYPE_class_upper _nl_C_LC_CTYPE_class_xdigit _nl_C_LC_CTYPE_map_tolower _nl_C_LC_CTYPE_map_toupper _nl_C_LC_CTYPE_tolower _nl_C_LC_CTYPE_toupper _nl_C_LC_CTYPE_width _nl_C_LC_IDENTIFICATION _nl_C_LC_MEASUREMENT _nl_C_LC_MESSAGES _nl_C_LC_MONETARY _nl_C_LC_NAME _nl_C_LC_NUMERIC _nl_C_LC_PAPER _nl_C_LC_TELEPHONE _nl_C_LC_TIME _nl_C_codeset _nl_C_locobj _nl_C_name _nl_POSIX_name _nl_category_name_sizes _nl_category_names _nl_category_num_items _nl_category_postload _nl_current _nl_current_LC_ADDRESS _nl_current_LC_COLLATE _nl_current_LC_CTYPE _nl_current_LC_IDENTIFICATION _nl_current_LC_MEASUREMENT _nl_current_LC_MESSAGES _nl_current_LC_MONETARY _nl_current_LC_NAME _nl_current_LC_NUMERIC _nl_current_LC_PAPER _nl_current_LC_TELEPHONE _nl_current_LC_TIME _nl_current_default_domain _nl_current_names _nl_default_default_domain _nl_default_dirname _nl_domain_bindings _nl_expand_alias _nl_explode_name _nl_find_domain _nl_find_language _nl_find_locale _nl_find_msg _nl_free_domain_conv _nl_get_alt_digit _nl_get_era_entry _nl_get_walt_digit _nl_init_domain_conv _nl_init_era_entries _nl_load_domain _nl_load_locale _nl_loaded_domains _nl_locale_file_list _nl_make_l10nflist _nl_msg_cat_cntr _nl_normalize_codeset _nl_parse_alt_digit _nl_postload_ctype _nl_postload_time _nl_remove_locale _nl_select_era_entry _nl_state_lock _nl_unload_domain _nl_unload_locale _nl_value_type_LC_ADDRESS _nl_value_type_LC_COLLATE _nl_value_type_LC_CTYPE _nl_value_type_LC_IDENTIFICATION _nl_value_type_LC_MEASUREMENT _nl_value_type_LC_MESSAGES _nl_value_type_LC_MONETARY _nl_value_type_LC_NAME _nl_value_type_LC_NUMERIC _nl_value_type_LC_PAPER _nl_value_type_LC_TELEPHONE _nl_value_type_LC_TIME _nl_value_types _pthread_cleanup_pop_restore _pthread_cleanup_push_defer _quicksort _r_debug _setjmp _start _sys_errlist _sys_nerr _tens_in_limb _tens_in_limb _tens_in_limb _tmbuf abort access add_dependency add_derivation add_module add_name_to_object add_to_global addmntent alias_compare aliasfile.1 alt_digits alt_digits_initialized arena_get2 arena_key arena_mem argz_add_sep argz_count argz_create_sep argz_stringify blanks blanks brk bsearch buf.2 buffered_vfprintf builtin_aliases builtin_modules cache cache_malloced cache_new cache_size cachesize call_gmon_start calloc capstr category_to_name cfree check_action chunk_align chunk_alloc chunk_free chunk_realloc clearenv close codeset_idx.0 collseqmb collseqwc completed.1 compute_change compute_tzname_max curwd.0 data data_start daylight dcgettext decompose_rpath default_gconv_path default_tzdir.0 derivation_compare detect_conflict disallow_malloc_check dl_open_worker do_always_noconv do_dlclose do_dlopen do_dlsym do_encoding do_in do_length do_max_length do_out do_release_all do_release_shlib do_unshift dummy_bucket.3 empty_path_elem endmntent env_path_list environ envlock era_initialized eras errno exit expand_dynamic_string_token expected.1 expected_note.2 extend_alias_table fclose fcloseall fcntl fgets_unlocked find_derivation find_module find_module_idx fini_dummy fixup flockfile flush_cleanup fopen force_to_data force_to_data fprintf frame_dummy fread_unlocked free free_atfork free_check free_derivation free_mem free_mem free_mem free_mem free_mem free_mem free_mem free_mem free_mem free_mem free_mem free_mem free_mem free_mem free_mem free_modules_db free_starter freemem.1 freemem_size.2 freeres fromidx fromlimit froms fseek ftrylockfile funlockfile gcc2_compiled. gcc2_compiled. gcc2_compiled. gcc2_compiled. gcc2_compiled. gconv_conf_filename gconv_module_ext gen_steps get_avphys_pages get_nprocs get_nprocs_conf get_phys_pages get_proc_path getcwd getdelim getdtablesize getegid getenv geteuid getgid getmntent_r getpagesize getpid getrlimit getuid group_number group_number gsignal guess_category_value hack_digit.0 hashfraction hasmntopt heap_trim increment_counter index init init_dummy init_dummy initial internal internal_trans_names.0 ioctl is_initialized.0 isatty isinf isinfl isnan isnanl jump_table.0 kcount kcountsize kill known_compare known_derivations known_values last_environ leaps list_all_lock list_lock llseek loaded locale_alias_path.0 localtime localtime_offset localtime_r lock lock lock lock lock lock lock.0 lock.1 log_hashfraction longjmp lose lowpc lseek lseek64 main main_arena main_trim mallinfo malloc malloc_atfork malloc_check malloc_get_state malloc_hook_ini malloc_set_state malloc_starter malloc_stats malloc_trim malloc_usable_size mallopt map map match_symbol max_capstrlen max_dirnamelen max_mmapped_mem max_n_mmaps max_sbrked_mem maxmap mbrlen mbrtowc mbsnrtowcs mem2chunk_check memalign memalign_check memalign_hook_ini memchr memcpy memmove mempcpy memset mktime mmap mmap_threshold mmapped_mem modcounter.0 mount_proc mprotect mremap msg.9 msort_with_tmp munmap n_mmaps n_mmaps_max narcs narcsp nbits.0 nbits.0 nbits.0 ncapstr new_do_write new_heap nmap not_available nsamples null num_eras num_leaps num_transitions num_types oact.0 object.2 old_tz once open open64 open_path open_verify openaux otimer.1 p.0 pagesize.1 path_proc pc_offset pc_scale phys_pages.0 phys_pages_info plone plural_eval plural_lookup plvar posix_memalign print_search_path printf printf_funcs printf_unknown profil profil_counter profile_fixup program_invocation_name program_invocation_short_name ptmalloc_init ptmalloc_init_all ptmalloc_lock_all ptmalloc_unlock_all pvalloc qsort raise rawmemchr read read_alias_file read_conf_file readlink realloc realloc_check realloc_hook_ini receiver register_printf_function release_handle result.1 rindex root rtld_search_dirs rule_dstoff rule_stdoff run_fp running samples save_arena save_for_backup save_for_wbackup save_free_hook save_malloc_hook sbrk sbrk_base search_tree setenv setitimer setlocale setmntent sigaction sigfillset siglongjmp sigprocmask sscanf stage state state state state stderr stdin stdout step0_jumps.1 step1_jumps.2 step2_jumps.3 step3a_jumps.4 step3b_jumps.5 step4_jumps.6 step4_jumps.7 stpcpy strcasecmp strchr strchrnul strcmp strcpy strdup strerror_r string_space string_space_act string_space_max strncasecmp strncmp strndup strnlen strpbrk strrchr strsep strstr strtod strtof strtol strtold strtoll strtoq strtoul strtoull strtouq sys_errlist sys_nerr sysconf system_dirs system_dirs_len tcgetattr tdelete tdestroy tdestroy_recurse textsize tfind timelocal timezone to_mb to_wc top_check top_pad tos trans_compare transcmp transitions translit_from_idx translit_from_tbl translit_to_idx translit_to_tbl transmem_list trecurse trim_threshold tsearch twalk type_idxs types tz_rules tzname tzset tzset_internal tzset_lock tzstring_list uname undefined_msg unsecure_envvars.0 unsetenv using_malloc_checking valloc vfprintf vfscanf vsscanf walt_digits walt_digits_initialized wcrtomb wcschr wcslen wcsnlen wcsrtombs wmemcpy wmemmove wmempcpy write writev yycheck yydefact yydefgoto yypact yypgoto yyr1 yyr2 yytable yytranslate zeroes zeroes zone_names The point is, /both/ libraries have a lot of code re-use. Dynamic linking puts that code re-use in some random .so in $foo/lib; static linking puts it in your executable. That's the major difference. (The minor difference is that most Haskell implementations use libc more than most C implementations use the Haskell standard libraries.)
This is not the fault of any particular implementation - the ghc-built binary has a similar collection - rather it is dictated by the nature of the language and its standard libraries. Because Prelude functions are small and re-usable, they do get used all over the place in the implementation of other parts of the Prelude, so you end up with a huge dependency graph hiding underneath the simplest of calls.
You mean like printf("Hello, world!\n")?
In fact, most of the extra stuff in "Hello World" is there purely to handle all possible error conditions in the I/O monad.
You mean as opposed to C, where most of the extra stuff is there purely to support number formatting?
Several years ago, Colin Runciman and I did the experiment of removing all the nice error-handling stuff from the prelude (and eliminating a few classes too I think), to see just how small we could squash "Hello World". The idea was to target embedded systems where memory is a scarce resource, and fancy error-reporting is pointless (a single red LED would do). IIRC, we managed to achieve a size of 25kb, compiled with nhc98, which don't forget includes a bytecode interpreter in the runtime system.
Regards, Malcolm
To sum up: code re-use within a library certainly happens in more languages than just Haskell :) So don't blame code re-use for Haskell-specific (or non-specific) problems, because code re-use is not a Haskell-specific cause. Jon Cast