salir reservadas programar peta para palabras opciones hacer español entornos desarrollo como haskell

reservadas - peta haskell en español



¿Hay una mejor manera de tener argumentos opcionales en Haskell? (5)

Estoy acostumbrado a poder definir argumentos opcionales como ese en Python:

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

Haskell no tiene argumentos predeterminados, pero pude obtener algo similar mediante el uso de Maybe:

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

Sin embargo, esto se vuelve engorroso muy rápidamente si tiene más de múltiples parámetros. Por ejemplo, ¿qué sucede si quiero hacer algo como esto?

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

Tendría que tener ocho definiciones de multiProduct para dar cuenta de todos los casos.

En cambio, decidí ir con esto:

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

Eso se ve muy poco elegante para mí. ¿Hay una forma idiomática de hacer esto en Haskell que sea más limpia?



Aquí hay otra forma de hacer argumentos opcionales en 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 -}

Entonces

{-# 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"

Actualización : Vaya, me aceptaron. Honestamente creo que la respuesta de luqui es la mejor aquí:

  • el tipo es claro y fácil de leer, incluso para principiantes
  • lo mismo para los errores de tipo
  • GHC no necesita sugerencias para hacer una inferencia de tipo con él (pruebe opt2 replicate 3 ''f'' en ghci para ver lo que quiero decir)
  • los argumentos opcionales son independientes de la orden

Cuando los argumentos se vuelven demasiado complejos, una solución es crear un tipo de datos solo para los argumentos. Luego puede crear un constructor predeterminado para ese tipo y completar solo lo que desea reemplazar en sus llamadas a funciones.

Ejemplo:

$ runhaskell dog.hs Snoopy (Beagle): Ruff! Snoopy (Beagle): Ruff! Wishbone (Terrier): Ruff! Wishbone (Terrier): Ruff! Wishbone (Terrier): Ruff!

dog.hs:

#!/usr/bin/env runhaskell import Control.Monad (replicateM_) data Dog = Dog { name :: String, breed :: String, barks :: Int } defaultDog :: Dog defaultDog = Dog { name = "Dog", breed = "Beagle", barks = 2 } bark :: Dog -> IO () bark dog = replicateM_ (barks dog) $ putStrLn $ (name dog) ++ " (" ++ (breed dog) ++ "): Ruff!" main :: IO () main = do bark $ defaultDog { name = "Snoopy", barks = 2 } bark $ defaultDog { name = "Wishbone", breed = "Terrier", barks = 3 }


No conozco una mejor manera de resolver el problema subyacente, pero su ejemplo puede escribirse de manera más sucinta como:

multiProduct req1 opt1 opt2 opt3 = req1 * opt1'' * opt2'' * opt3'' where opt1'' = fromMaybe 10 opt1 opt2'' = fromMaybe 20 opt2 opt3'' = fromMaybe 30 opt3


Tal vez una buena notación sería más fácil para los ojos:

(//) :: Maybe a -> a -> a Just x // _ = x Nothing // y = y -- basically fromMaybe, just want to be transparent multiProduct req1 opt1 opt2 opt3 = req1 * (opt1 // 10) * (opt2 // 20) * (opt3 // 30)

Si necesita usar los parámetros más de una vez, sugiero ir con el método de @ pat.

EDIT 6 años después

Con ViewPatterns puede poner los valores predeterminados a la izquierda.

{-# LANGUAGE ViewPatterns #-} import Data.Maybe (fromMaybe) def :: a -> Maybe a -> a def = fromMaybe multiProduct :: Int -> Maybe Int -> Maybe Int -> Maybe Int -> Int multiProduct req1 (def 10 -> opt1) (def 20 -> opt2) (def 30 -> opt3) = req1 * opt1 * opt2 * opt3