在Haskell中是否有更好的方法来具有可选函数参数? [英] Is there a better way to have optional function arguments in Haskell?

查看:73
本文介绍了在Haskell中是否有更好的方法来具有可选函数参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我习惯于像Python中那样定义可选参数:

I'm used to being able to define optional arguments like so in Python:

def product(a, b=2):
    return a * b

Haskell没有默认参数,但是我可以通过使用Maybe得到类似的东西:

Haskell doesn't have default arguments, but I was able to get something similar by using a Maybe:

product a (Just b) = a * b
product a Nothing = a * 2

但是,如果您拥有多个参数,这将变得非常麻烦.例如,如果我想做这样的事情怎么办:

This becomes cumbersome very quickly if you have more than multiple parameters though. For example, what if I want to do something like this:

def multiProduct (a, b=10, c=20, d=30):
    return a * b * c * d

要考虑所有情况,我必须具有multiProduct的八个定义.

I would have to have eight definitions of multiProduct to account for all cases.

相反,我决定继续这样做:

Instead, I decided to go with this:

multiProduct req1 opt1 opt2 opt3 = req1 * opt1' * opt2' * opt3'
    where opt1' = if isJust opt1 then (fromJust opt1) else 10
    where opt2' = if isJust opt2 then (fromJust opt2) else 20
    where opt3' = if isJust opt3 then (fromJust opt3) else 30

对我来说,这看起来很微不足道.在Haskell中,是否有惯用的方式做到这一点?

That looks very inelegant to me. Is there an idiomatic way to do this in Haskell that is cleaner?

推荐答案

这是在Haskell中执行可选参数的另一种方法:

Here's yet another way to do optional arguments in Haskell:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-}
module Optional where

class Optional1 a b r where 
  opt1 :: (a -> b) -> a -> r

instance Optional1 a b b where
  opt1 = id

instance Optional1 a b (a -> b) where
  opt1 = const

class Optional2 a b c r where 
  opt2 :: (a -> b -> c) -> a -> b -> r

instance Optional2 a b c c where
  opt2 = id

instance (Optional1 b c r) => Optional2 a b c (a -> r) where
  opt2 f _ b = \a -> opt1 (f a) b

{- Optional3, Optional4, etc defined similarly -}

然后

{-# LANGUAGE FlexibleContexts #-}
module Main where
import Optional

foo :: (Optional2 Int Char String r) => r
foo = opt2 replicate 3 'f'

_5 :: Int
_5 = 5

main = do
  putStrLn $ foo        -- prints "fff"
  putStrLn $ foo _5     -- prints "fffff"
  putStrLn $ foo _5 'y' -- prints "yyyyy"


更新:糟糕,我被接受了.老实说,我认为 luqui的答案是这里最好的:


Update: Whoops, I got accepted. I honestly think that luqui's answer is the best one here:

  • 即使对于初学者,类型也清晰易读
  • 相同的类型错误
  • GHC不需要提示来进行类型推断(尝试在ghci中尝试opt2 replicate 3 'f'来了解我的意思)
  • 可选参数与顺序无关
  • the type is clear, and easy to read, even for beginners
  • same for type errors
  • GHC doesn't need hints to do type inference with it (try opt2 replicate 3 'f' in ghci to see what I mean)
  • the optional arguments are order-independent

这篇关于在Haskell中是否有更好的方法来具有可选函数参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆